home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / fgl110b.zip / USER2.TXT < prev   
Text File  |  1992-02-07  |  323KB  |  7,674 lines

  1.  
  2.  
  3. Chapter 9
  4.  
  5. Images and
  6. Image Management
  7. 136  Fastgraph User's Guide
  8.  
  9.  
  10. Overview
  11.  
  12.      Within the context of Fastgraph, an image is a rectangular area of video
  13. memory containing some type of picture.  An image might be something as
  14. simple as a pointing hand icon, or as detailed as the dashboard of a sports
  15. car.  Fastgraph includes several routines to display, retrieve, and
  16. manipulate images, as well as transfer them between different areas of video
  17. memory.  This chapter will discuss these routines in detail.  The information
  18. presented here, combined with the video page management techniques described
  19. in the previous chapter, will provide the tools we need for sophisticated
  20. animation techniques.
  21.  
  22.  
  23. Mode-Independent Bit-Mapped Images
  24.  
  25.      This section will discuss the image display routines that use the same
  26. bit-mapped image format for all graphics video modes.  Another class of
  27. routines, described in the next section, use different formats for different
  28. video modes.  While these mode-independent image display routines are more
  29. general, they achieve this generality at the sake of execution speed.  This
  30. may especially be a concern if the image is large, or if speed is critical in
  31. an application (as in arcade-style graphics).  For many programs, however,
  32. the mode-independent routines provide all the image display capability
  33. needed.
  34.  
  35.      Let's begin with an example of a very simple image.  Suppose we need to
  36. display a small triangle whose perimeter is a different color than its
  37. interior.  To use this image with Fastgraph, we must inscribe it in a
  38. rectangular area.  Hence, the pixel representation of our triangle might
  39. appear as shown below.
  40.  
  41.                               . . . . * . . . .
  42.                               . . . * x * . . .
  43.                               . . * x x x * . .
  44.                               . * x x x x x * .
  45.                               * * * * * * * * *
  46.  
  47.      As shown in this diagram, our triangle is 9 pixels wide at its base and
  48. 5 pixels high.  The pixels indicated by an asterisk (*) are the triangle's
  49. perimeter, while those indicated by an x represent its interior points.  We
  50. need to distinguish between these pixels because they will be different
  51. colors.  The pixels shown as periods (.) are not part of the triangle itself.
  52. They are required to make the image rectangular, so from Fastgraph's
  53. perspective they are indeed part of the image.
  54.  
  55.      The Fastgraph routine fg_drawmap is a suitable routine for drawing our
  56. triangle.  To use fg_drawmap, we must create separate bit maps for each color
  57. in the image (excluding the points used to fill the rectangular region, which
  58. is considered transparent).  In this example, we will thus need two bit
  59. maps -- one for the perimeter points, and one for the interior points.  Let's
  60. break the image into these two bit maps.
  61.                                   Chapter 9:  Images and Image Management  137
  62.  
  63.                   . . . . * . . . .        . . . . . . . . .
  64.                   . . . * . * . . .        . . . . x . . . .
  65.                   . . * . . . * . .        . . . x x x . . .
  66.                   . * . . . . . * .        . . x x x x x . .
  67.                   * * * * * * * * *        . . . . . . . . .
  68.  
  69.                   perimeter points          interior points
  70.  
  71.      The next step is to convert these two bit maps into their binary
  72. representations.  Just as there are eight bits in a byte, we will create a
  73. data structure (an array in this case) with each byte holding eight pixels.
  74. Bits that are set (1) indicate the corresponding pixel will appear displayed
  75. in the color associated with that bit map.  Bits that are reset (0) leave the
  76. corresponding pixel unchanged.  The size of each bit map array must be at
  77. least 10 bytes because each bit map contains five rows with nine pixels in
  78. each row (that is, two bytes are required for each row of the image).  Hence,
  79. when we convert these bit maps to their binary representations, and
  80. subsequently to their hexadecimal equivalent, the results will appear as
  81. shown below.  The boldface bits represent the actual image; the other bits
  82. are filler bits needed to complete each row of the bit maps after the ninth
  83. pixel.  All filler bits must be zero.
  84.  
  85.               0 0 0 0 1 0 0 0   0 0 0 0 0 0 0 0         08   00
  86.               0 0 0 1 0 1 0 0   0 0 0 0 0 0 0 0         14   00
  87.               0 0 1 0 0 0 1 0   0 0 0 0 0 0 0 0         22   00
  88.               0 1 0 0 0 0 0 1   0 0 0 0 0 0 0 0         41   00
  89.               1 1 1 1 1 1 1 1   1 0 0 0 0 0 0 0         FF   80
  90.  
  91.                               perimeter bit map
  92.  
  93.  
  94.               0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0         00   00
  95.               0 0 0 0 1 0 0 0   0 0 0 0 0 0 0 0         08   00
  96.               0 0 0 1 1 1 0 0   0 0 0 0 0 0 0 0         1C   00
  97.               0 0 1 1 1 1 1 0   0 0 0 0 0 0 0 0         3E   00
  98.               0 0 0 0 0 0 0 0   0 0 0 0 0 0 0 0         00   00
  99.  
  100.                                interior bit map
  101.  
  102.      The next question is the order in which the bit maps are stored in the
  103. corresponding data structures.  Since our data structure is an array, it is
  104. only necessary to show the relationship of the subscripts to the bit map
  105. structures above.  The next diagram shows the subscript order for the case of
  106. a two-column by five-row bit map.
  107.  
  108.                                   [8]   [9]
  109.  
  110.                                   [6]   [7]
  111.  
  112.                                   [4]   [5]
  113.  
  114.                                   [2]   [3]
  115.  
  116.                                   [0]   [1]
  117.  
  118. 138  Fastgraph User's Guide
  119.  
  120.  
  121.      From this diagram, we see the first element of the array (that is, the
  122. element with subscript [0]) represents the lower left corner of the image.
  123. The subscript progression then continues right until reaching the end of the
  124. first row.  It then resumes at the leftmost element of the second row and
  125. continues to the right until the end of that row.  It continues in this
  126. manner for all remaining rows.
  127.  
  128.      We are now ready to present an example program to display our triangle.
  129. The program will use the Fastgraph routine fg_drawmap, which expects three
  130. arguments.  The first argument is the bit map array (passed by reference),
  131. the second is the width of the bit map in bytes, and the last is the height
  132. of the bit map in pixel rows.  The fg_drawmap routine displays the image such
  133. that its lower left corner is at the graphics cursor position on the active
  134. video page.  The routine has no effect in text video modes.  Additionally,
  135. fg_drawmap displays the image using the current color index, which means we
  136. will need to call fg_drawmap once for each color in the image.
  137.  
  138.      Example 9-1 runs in any 320 by 200 color graphics mode (it could be made
  139. to run in mode 12 too, but that would detract from the purpose of the
  140. example).  After establishing the video mode, the program uses fg_rect to
  141. fill the entire screen with a gray rectangle (white in CGA).  Next, the
  142. program establishes (156,101) as the graphics cursor position; this causes
  143. the triangle to be centered on the screen.  The two calls to fg_drawmap, one
  144. for each of the colors in the image, actually display the triangle.  Note
  145. especially how fg_setcolor is used before each call to fg_drawmap to define
  146. the current color index.  The result is a triangle with a blue perimeter
  147. (cyan in CGA) and green interior (magenta in CGA).
  148.  
  149.                                  Example 9-1.
  150.  
  151.              #include <fastgraf.h>
  152.              #include <stdio.h>
  153.              #include <stdlib.h>
  154.              void main(void);
  155.  
  156.              char perimeter[] = {
  157.                 0xFF,0x80,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00
  158.                 };
  159.              char interior[] = {
  160.                 0x00,0x00,0x3E,0x00,0x1C,0x00,0x08,0x00,0x00,0x00
  161.                 };
  162.  
  163.              void main()
  164.              {
  165.                 int old_mode, new_mode;
  166.  
  167.                 new_mode = fg_bestmode(320,200,1);
  168.                 if (new_mode < 0 || new_mode == 12) {
  169.                    printf("This program requires a 320 ");
  170.                    printf("x 200 color graphics mode.\n");
  171.                    exit(1);
  172.                    }
  173.  
  174.                 old_mode = fg_getmode();
  175.                 fg_setmode(new_mode);
  176.  
  177.                                   Chapter 9:  Images and Image Management  139
  178.  
  179.  
  180.                 fg_setcolor(7);
  181.                 fg_rect(0,319,0,199);
  182.  
  183.                 fg_move(156,101);
  184.                 fg_setcolor(1);
  185.                 fg_drawmap(perimeter,2,5);
  186.                 fg_setcolor(2);
  187.                 fg_drawmap(interior,2,5);
  188.                 fg_waitkey();
  189.  
  190.                 fg_setmode(old_mode);
  191.                 fg_reset();
  192.              }
  193.  
  194.  
  195.      The different color bit maps used by fg_drawmap do not all have to be
  196. the same size.  In our triangle example, the perimeter is 9 pixels wide by 5
  197. pixels high, but the interior is only 5 pixels wide by 3 pixels high.  Hence,
  198. the bit map for the interior pixels only requires one byte for each of its
  199. three rows, so we can store it in a three-byte array.  Its structure would
  200. be:
  201.  
  202.                                   [2]   08
  203.                                   [1]   1C
  204.                                   [0]   3E
  205.  
  206.      Example 9-2 is similar to example 9-1, but it uses a three-byte array
  207. for the interior bit map.  Note the second call to fg_move in this example.
  208. It is needed because the bottom row of the smaller interior bit map
  209. corresponds to the second row of the larger perimeter bit map.  In other
  210. words, the interior bit map must be displayed one row above the perimeter bit
  211. map.
  212.  
  213.                                  Example 9-2.
  214.  
  215.              #include <fastgraf.h>
  216.              #include <stdio.h>
  217.              #include <stdlib.h>
  218.              void main(void);
  219.  
  220.              char perimeter[] = {
  221.                 0xFF,0x80,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00
  222.                 };
  223.              char interior[] = {
  224.                 0x3E,0x1C,0x08
  225.                 };
  226.  
  227.              void main()
  228.              {
  229.                 int old_mode, new_mode;
  230.  
  231.                 new_mode = fg_bestmode(320,200,1);
  232.                 if (new_mode < 0 || new_mode == 12) {
  233.  
  234. 140  Fastgraph User's Guide
  235.  
  236.                    printf("This program requires a 320 ");
  237.                    printf("x 200 color graphics mode.\n");
  238.                    exit(1);
  239.                    }
  240.  
  241.                 old_mode = fg_getmode();
  242.                 fg_setmode(new_mode);
  243.  
  244.                 fg_setcolor(7);
  245.                 fg_rect(0,319,0,199);
  246.  
  247.                 fg_move(156,101);
  248.                 fg_setcolor(1);
  249.                 fg_drawmap(perimeter,2,5);
  250.                 fg_move(156,100);
  251.                 fg_setcolor(2);
  252.                 fg_drawmap(interior,1,3);
  253.                 fg_waitkey();
  254.  
  255.                 fg_setmode(old_mode);
  256.                 fg_reset();
  257.              }
  258.  
  259.      In example 9-2, the time required to execute the second call to fg_move
  260. may not be worth the saving of 7 bytes.  When array space is critical, or
  261. when the images are larger, the use of smaller bit maps for certain colors
  262. may be more valuable.
  263.  
  264.      Yet another possibility for example 9-2 would be to shift the elements
  265. of the interior bit map two pixels to the left.  In this way, the bit map
  266. would be aligned against the left side of the array, just as the perimeter
  267. bit map is.  The three values comprising the interior bit map would then
  268. become F8, 70, and 20.  We also would need to change the x coordinate in the
  269. second call to fg_move from 156 to 158.
  270.  
  271.  
  272. Mode-Specific Bit-Mapped Images
  273.  
  274.      This section will discuss the image display routines that use bit-mapped
  275. image formats that are specific to each text and graphics video mode.  The
  276. different image formats closely resemble the structure of video memory in
  277. each mode, so these routines are much faster than displaying mode-independent
  278. bit maps with fg_drawmap.  If you use the mode-specific bit maps in a program
  279. that supports several video modes, there will be some additional programming
  280. that is not needed when using mode-independent bit maps.  Usually, however,
  281. your efforts will be rewarded with faster graphics.
  282.  
  283.      We'll demonstrate the use of mode-specific bit maps in graphics modes
  284. with the familiar two-color triangle whose pixel representation appears
  285. below.
  286.  
  287.                               . . . . * . . . .
  288.                               . . . * x * . . .
  289.                               . . * x x x * . .
  290.                               . * x x x x x * .
  291.                               * * * * * * * * *
  292.                                   Chapter 9:  Images and Image Management  141
  293.  
  294.      As before, our triangle is 9 pixels wide at its base and 5 pixels high.
  295. The pixels indicated by an asterisk (*) are the triangle's perimeter, while
  296. those indicated by an x represent its interior points.  We need to
  297. distinguish between these pixels because they will be different colors.  The
  298. pixels shown as periods (.) are not part of the triangle itself.  They are
  299. required to make the image rectangular, so from Fastgraph's perspective they
  300. are indeed part of the image.
  301.  
  302.  
  303. Regular Images
  304.  
  305.      The Fastgraph routine fg_drwimage displays regular mode-specific bit-
  306. mapped images (by regular, we mean an image that is neither clipped nor
  307. rotated).  Its arguments are the same as for the fg_drawmap routine, and the
  308. bit map array's subscript order is also the same as for fg_drawmap.  The
  309. major difference is the bit map structure -- we combine the information for
  310. all colors into a single bit map, in a way consistent with the structure and
  311. accessibility of video memory for the various modes.  As with the other image
  312. display routines, fg_drwimage displays the image on the active video page
  313. with its lower left corner at the graphics cursor position (or the text
  314. cursor position for text modes).  We'll now examine the use of fg_drwimage in
  315. several video modes.
  316.  
  317. CGA four-color graphics modes
  318.  
  319.      In the four-color CGA graphics modes (modes 4 and 5), each pixel can
  320. assume a value between 0 and 3.  This means it takes two bits to represent a
  321. pixel, or put another way, each byte of video memory holds four pixels.  Our
  322. triangle image is nine pixels wide, so three bytes are needed for each row of
  323. the image.  Because the image is five pixels high, we need a bit map array of
  324. at least 15 bytes (five rows times three bytes per row) to hold the image.
  325.  
  326.      The image's binary representation and its hexadecimal equivalent for the
  327. four-color CGA graphics modes are shown below.  The binary values in boldface
  328. represent the actual image; the others are the filler bits needed to complete
  329. each row of the bit map after the ninth pixel.  We have coded the perimeter
  330. pixels to be color 1 (01 binary) and the interior pixels to be color 2 (10
  331. binary).  Any pixel whose value is zero (00 binary) is transparent and will
  332. thus leave the contents of video memory at that position unchanged.
  333.  
  334.          00 00 00 00   01 00 00 00   00 00 00 00         00   40   00
  335.          00 00 00 01   10 01 00 00   00 00 00 00         01   90   00
  336.          00 00 01 10   10 10 01 00   00 00 00 00         06   A4   00
  337.          00 01 10 10   10 10 10 01   00 00 00 00         1A   A9   00
  338.          01 01 01 01   01 01 01 01   01 00 00 00         55   55   40
  339.  
  340.      Example 9-3 uses this mode-specific bit map to display the triangle in
  341. the standard CGA four-color graphics mode (mode 4).  After establishing the
  342. video mode, the program uses fg_rect to fill the entire screen with a white
  343. rectangle.  Next, the program establishes (156,101) as the graphics cursor
  344. position; this causes the triangle to be centered on the screen.  The call to
  345. 142  Fastgraph User's Guide
  346.  
  347. fg_drwimage produces a triangle with a cyan perimeter (color 1) and a magenta
  348. interior (color 2).
  349.  
  350.                                  Example 9-3.
  351.  
  352.               #include <fastgraf.h>
  353.               #include <stdio.h>
  354.               #include <stdlib.h>
  355.               void main(void);
  356.  
  357.               char triangle[] = {
  358.                  0x55,0x55,0x40, 0x1A,0xA9,0x00, 0x06,0xA4,0x00,
  359.                  0x01,0x90,0x00, 0x00,0x40,0x00
  360.                  };
  361.  
  362.               void main()
  363.               {
  364.                  int old_mode;
  365.  
  366.                  if (fg_testmode(4,1) == 0) {
  367.                     printf("This program requires a 320 ");
  368.                     printf("x 200 CGA graphics mode.\n");
  369.                     exit(1);
  370.                     }
  371.  
  372.                  old_mode = fg_getmode();
  373.                  fg_setmode(4);
  374.  
  375.                  fg_setcolor(7);
  376.                  fg_rect(0,319,0,199);
  377.  
  378.                  fg_move(156,101);
  379.                  fg_drwimage(triangle,3,5);
  380.                  fg_waitkey();
  381.  
  382.                  fg_setmode(old_mode);
  383.                  fg_reset();
  384.               }
  385.  
  386.  
  387. CGA two-color graphics mode
  388.  
  389.      In the two-color CGA graphics mode (mode 6), each pixel can assume the
  390. values 0 or 1.  This means it takes just one bit to represent a pixel, so
  391. each byte of video memory holds eight pixels.  Our triangle image is nine
  392. pixels wide, so two bytes are needed for each row of the image.  Because the
  393. image is five pixels high, we need a bit map array of at least 10 bytes (five
  394. rows times two bytes per row) to hold the image.
  395.  
  396.      The image's binary representation and its hexadecimal equivalent for the
  397. two-color CGA graphics mode is shown below.  The binary values in boldface
  398. represent the actual image; the others are the filler bits needed to complete
  399. each row of the bit map after the ninth pixel.  We have coded both the
  400. perimeter pixels and the interior pixels to be color 1.  Any pixel whose
  401. value is zero is transparent and will thus leave the contents of video memory
  402. at that position unchanged.
  403.                                   Chapter 9:  Images and Image Management  143
  404.  
  405.               0 0 0 0 1 0 0 0   0 0 0 0 0 0 0 0         08   00
  406.               0 0 0 1 1 1 0 0   0 0 0 0 0 0 0 0         1C   00
  407.               0 0 1 1 1 1 1 0   0 0 0 0 0 0 0 0         3E   00
  408.               0 1 1 1 1 1 1 1   0 0 0 0 0 0 0 0         7F   00
  409.               1 1 1 1 1 1 1 1   1 0 0 0 0 0 0 0         FF   80
  410.  
  411.      Example 9-4 uses this mode-specific bit map to display the triangle in
  412. the CGA two-color graphics mode (mode 6).  After establishing the video mode,
  413. the program establishes (316,101) as the graphics cursor position; this
  414. causes the triangle to be centered on the screen.  The call to fg_drwimage
  415. produces a solid triangle.
  416.  
  417.                                  Example 9-4.
  418.  
  419.                   #include <fastgraf.h>
  420.                   #include <stdio.h>
  421.                   #include <stdlib.h>
  422.                   void main(void);
  423.  
  424.                   char triangle[] = {
  425.                      0xFF,0x80, 0x7F,0x00, 0x3E,0x00,
  426.                      0x1C,0x00, 0x08,0x00
  427.                      };
  428.  
  429.                   void main()
  430.                   {
  431.                      int old_mode;
  432.  
  433.                      if (fg_testmode(6,1) == 0) {
  434.                         printf("This program requires a ");
  435.                         printf("CGA graphics mode.\n");
  436.                         exit(1);
  437.                         }
  438.  
  439.                      old_mode = fg_getmode();
  440.                      fg_setmode(6);
  441.  
  442.                      fg_move(316,101);
  443.                      fg_drwimage(triangle,2,5);
  444.                      fg_waitkey();
  445.  
  446.                      fg_setmode(old_mode);
  447.                      fg_reset();
  448.                   }
  449.  
  450.  
  451. Tandy/PCjr 16-color graphics mode
  452.  
  453.      The structure of the mode-specific bit maps for the Tandy/PCjr 16-color
  454. graphics mode (mode 9) is the same as the mode-specific bit map structure for
  455. the native EGA and VGA graphics modes.  Please refer to page 144 for a
  456. discussion of EGA and VGA bit maps.
  457. 144  Fastgraph User's Guide
  458.  
  459. Hercules graphics modes
  460.  
  461.      The structure of the mode-specific bit maps for the Hercules graphics
  462. modes (modes 11 and 12) is the same as two of the CGA graphics modes.  For
  463. the standard Hercules graphics mode (mode 11), please refer to the discussion
  464. of CGA two-color (mode 6) bit maps on page 142.  For the low-resolution
  465. Hercules graphics mode (mode 12), please refer to the discussion of the CGA
  466. four-color (mode 4) bit maps on page 141.
  467.  
  468. EGA and VGA graphics modes
  469.  
  470.      In the native EGA and VGA graphics modes (modes 13 through 18), each
  471. pixel can assume a value between 0 and 15.  This means it takes four bits to
  472. represent a pixel, so each byte of the bit map holds two pixels.  Our
  473. triangle image is nine pixels wide, so five bytes are needed for each row of
  474. the image.  Because the image is five pixels high, we need a bit map array of
  475. at least 25 bytes (five rows times five bytes per row) to hold the image.
  476.  
  477.      In these modes, it is easy to develop the hexadecimal representation of
  478. a bit map without first producing its binary equivalent.  This is because a
  479. pixel value and a hexadecimal digit each occupy four bits.  The triangle's
  480. hexadecimal representation for the native EGA and VGA modes is shown below.
  481. The pixels in boldface represent the actual image; the others are the filler
  482. values needed to complete each row of the bit map after the ninth pixel.  We
  483. have chosen to display the perimeter pixels in color 1 and the interior
  484. pixels in color 2.  Any pixel whose value is zero is transparent and will
  485. thus leave the contents of video memory at that position unchanged.
  486.  
  487.                             00   00   10   00   00
  488.                             00   01   21   00   00
  489.                             00   12   22   10   00
  490.                             01   22   22   21   00
  491.                             11   11   11   11   10
  492.  
  493.      Example 9-5 is similar to example 9-3, but it uses the 320 x 200 EGA
  494. graphics mode (mode 13) and the mode-specific bit map just constructed to
  495. display the triangle.  The call to fg_drwimage produces a triangle with a
  496. blue perimeter (color 1) and a green interior (color 2).
  497.  
  498.                                  Example 9-5.
  499.  
  500.                 #include <fastgraf.h>
  501.                 #include <stdio.h>
  502.                 #include <stdlib.h>
  503.                 void main(void);
  504.  
  505.                 char triangle[] = {
  506.                    0x11,0x11,0x11,0x11,0x10,
  507.                    0x01,0x22,0x22,0x21,0x00,
  508.                    0x00,0x12,0x22,0x10,0x00,
  509.                    0x00,0x01,0x21,0x00,0x00,
  510.                    0x00,0x00,0x10,0x00,0x00
  511.                    };
  512.  
  513.                                   Chapter 9:  Images and Image Management  145
  514.  
  515.                 void main()
  516.                 {
  517.                    int old_mode;
  518.  
  519.                    if (fg_testmode(13,1) == 0) {
  520.                       printf("This program requires a 320 ");
  521.                       printf("x 200 EGA graphics mode.\n");
  522.                       exit(1);
  523.                       }
  524.  
  525.                    old_mode = fg_getmode();
  526.                    fg_setmode(13);
  527.  
  528.                    fg_setcolor(7);
  529.                    fg_rect(0,319,0,199);
  530.  
  531.                    fg_move(156,101);
  532.                    fg_drwimage(triangle,5,5);
  533.                    fg_waitkey();
  534.  
  535.                    fg_setmode(old_mode);
  536.                    fg_reset();
  537.                 }
  538.  
  539.  
  540. MCGA and VGA 256-color graphics modes
  541.  
  542.      In the MCGA and VGA 256-color graphics modes (modes 19 through 23), each
  543. pixel can assume a value between 0 and 255 (FF hex).  This means it takes
  544. eight bits to represent a pixel, or each byte of video memory holds one
  545. pixel.  Our triangle image is nine pixels wide, so nine bytes are needed for
  546. each row of the image.  Because the image is five pixels high, we need a bit
  547. map array of at least 45 bytes (five rows times nine bytes per row) to hold
  548. the image.  Note we will never need any filler bits in the 256-color video
  549. modes.
  550.  
  551.      In the 256-color graphics video modes, it is simple to develop the bit
  552. map for an image because each byte holds exactly one pixel.  The triangle's
  553. hexadecimal representation for the 256-color graphics modes is shown below.
  554. As before, we have coded the perimeter pixels to be color 1 (01 hex) and the
  555. interior pixels to be color 2 (02 hex).  Any pixel whose value is zero is
  556. transparent and will thus leave the contents of video memory at that position
  557. unchanged.
  558.  
  559.                   00   00   00   00   01   00   00   00   00
  560.                   00   00   00   01   02   01   00   00   00
  561.                   00   00   01   02   02   02   01   00   00
  562.                   00   01   02   02   02   02   02   01   00
  563.                   01   01   01   01   01   01   01   01   01
  564.  
  565. 146  Fastgraph User's Guide
  566.  
  567.      Example 9-6 is also similar to example 9-3, but it uses the MCGA 256-
  568. color graphics mode (mode 19) and the mode-specific bit map just constructed
  569. to display the triangle.  The call to fg_drwimage produces a triangle with a
  570. blue perimeter (color 1) and a green interior (color 2).
  571.  
  572.                                  Example 9-6.
  573.  
  574.                #include <fastgraf.h>
  575.                #include <stdio.h>
  576.                #include <stdlib.h>
  577.                void main(void);
  578.  
  579.                char triangle[] = {
  580.                   0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
  581.                   0x00,0x01,0x02,0x02,0x02,0x02,0x02,0x01,0x00,
  582.                   0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00,
  583.                   0x00,0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x00,
  584.                   0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00
  585.                   };
  586.  
  587.                void main()
  588.                {
  589.                   int old_mode;
  590.  
  591.                   if (fg_testmode(19,1) == 0) {
  592.                      printf("This program requires a 320 ");
  593.                      printf("x 200 MCGA graphics mode.\n");
  594.                      exit(1);
  595.                      }
  596.  
  597.                   old_mode = fg_getmode();
  598.                   fg_setmode(19);
  599.  
  600.                   fg_setcolor(7);
  601.                   fg_rect(0,319,0,199);
  602.  
  603.                   fg_move(156,101);
  604.                   fg_drwimage(triangle,9,5);
  605.                   fg_waitkey();
  606.  
  607.                   fg_setmode(old_mode);
  608.                   fg_reset();
  609.                }
  610.  
  611.  
  612.  
  613. Text Modes
  614.  
  615.      You also can use the fg_drwimage routine to display images in text video
  616. modes (modes 0, 1, 2, 3, and 7).  As one might expect, the image structure in
  617. the text modes is rather different from the graphics modes.  In Chapter 5 we
  618. saw that each character cell on the screen actually consists of a character
  619. and an attribute.  The character value determines what character is
  620. displayed, while the attribute value controls the character's appearance.
  621. The structure of the attribute is:
  622.                                   Chapter 9:  Images and Image Management  147
  623.  
  624.  
  625.                             bits  attribute
  626.  
  627.                             0-3   foreground color
  628.                             4-6   background color
  629.                              7    blinking
  630.  
  631.      The text mode image structure used with fg_drwimage also consists of a
  632. series of characters and attributes.  For example, the following diagram
  633. illustrates the structure of an image that is three characters wide and two
  634. characters high.
  635.  
  636.                    char   attr   char   attr   char   attr
  637.  
  638.                    char   attr   char   attr   char   attr
  639.  
  640.      To illustrate the use of fg_drwimage in a text video mode, we'll display
  641. the phrase "hello there" on two different lines in the center of the screen.
  642. Furthermore, let's assume we would like the first character of each word to
  643. appear in foreground color 1, the second in color 2, and so forth.  Our image
  644. will consist of two lines each containing five characters, and each character
  645. requires two bytes of storage (one for the character and another for its
  646. attribute), so we'll need a 20-byte array for holding the image.  The array
  647. really doesn't hold a bit map as in the graphics modes, so in the text modes
  648. the first argument passed to fg_drwimage is instead called the image array.
  649. In our example, the structure of the image array is:
  650.  
  651.            'h'    1    'e'    2    'l'    3    'l'    4    'o'    5
  652.  
  653.            't'    1    'h'    2    'e'    3    'r'    4    'e'    5
  654.  
  655. The subscript order that fg_drwimage uses for text modes is the same as for
  656. the graphics modes.  For our five-row by two-column image, this means the
  657. array subscripts would be numbered as follows:
  658.  
  659.               [10] [11] [12] [13] [14] [15] [16] [17] [18] [19]
  660.  
  661.                [0]  [1]  [2]  [3]  [4]  [5]  [6]  [7]  [8]  [9]
  662.  
  663.      Depending on the character and attribute values in the image array,
  664. fg_drwimage can display new characters and attributes, new characters leaving
  665. the existing attribute unchanged, new attributes leaving the existing
  666. character unchanged, or leave both the existing character and attribute
  667. unchanged in video memory.  To keep an existing character or attribute,
  668. simply specify a value of 0 in the corresponding element of the image array.
  669. This capability is analogous to the fact that zero-valued pixels in graphics
  670. mode bit maps leave video memory unchanged.
  671. 148  Fastgraph User's Guide
  672.  
  673.      Example 9-7 demonstrates the use of the fg_drwimage routine in the 80-
  674. column color text mode (mode 3).  After establishing the video mode and
  675. making the cursor invisible, the program calls fg_drwimage to display the
  676. "hello there" image just discussed (note we pass the dimensions of the image
  677. array as the number of bytes, not the number of characters).  The program
  678. waits for a keystroke and then calls fg_drwimage again, passing a different
  679. image array (called "image") of the same size.  This array changes the first
  680. letter of both words from lower case to upper case (leaving the attribute
  681. unchanged), and it makes the remaining characters have the same attribute as
  682. the first character.  This is done in part by using zero-valued characters
  683. and attributes to leave video memory unchanged.  After waiting for another
  684. keystroke, the program exits.
  685.  
  686.                                  Example 9-7.
  687.  
  688.                     #include <fastgraf.h>
  689.                     void main(void);
  690.  
  691.                     char hello[] = {
  692.                        't',1, 'h',2, 'e',3, 'r',4, 'e',5,
  693.                        'h',1, 'e',2, 'l',3, 'l',4, 'o',5
  694.                        };
  695.  
  696.                     char image[] = {
  697.                        'T',0, 0,1, 0,1, 0,1, 0,1,
  698.                        'H',0, 0,1, 0,1, 0,1, 0,1
  699.                        };
  700.  
  701.                     void main()
  702.                     {
  703.                        int old_mode;
  704.  
  705.                        old_mode = fg_getmode();
  706.                        fg_setmode(3);
  707.                        fg_cursor(0);
  708.  
  709.                        fg_locate(12,37);
  710.                        fg_drwimage(hello,10,2);
  711.                        fg_waitkey();
  712.  
  713.                        fg_drwimage(image,10,2);
  714.                        fg_waitkey();
  715.  
  716.                        fg_setmode(old_mode);
  717.                        fg_reset();
  718.                     }
  719.  
  720.  
  721. Clipped Images
  722.  
  723.      The fg_drwimage routine displays an image without regard to the current
  724. clipping limits.  If you want the image to be displayed with respect to the
  725. clipping limits (as established by the most recent call to fg_setclip), you
  726. should use the fg_clpimage routine instead of fg_drwimage.  Fg_clpimage takes
  727. the same three arguments as fg_drwimage, and also displays the image such
  728. that its lower left corner is at the graphics cursor position.  Unlike
  729. fg_drwimage, the fg_clpimage routine has no effect when used in a text video
  730.                                   Chapter 9:  Images and Image Management  149
  731.  
  732. mode.  Refer to pages 149 and 151 for example programs that use fg_clpimage.
  733. Because of the additional overhead involved in checking the clipping limits,
  734. fg_clpimage is not as fast as fg_drwimage.
  735.  
  736.  
  737. Reversed Images
  738.  
  739.      The fg_revimage routine displays an image reversed (that is, mirrored
  740. about the y-axis).  Fg_revimage takes the same three arguments as
  741. fg_drwimage, and also displays the image such that its lower left corner is
  742. at the graphics cursor position.  The fg_revimage routine has no effect when
  743. used in a text video mode.  Refer to pages 150 and 151 for example programs
  744. that use fg_revimage.
  745.  
  746.  
  747. Reversed Clipped Images
  748.  
  749.      The fg_flpimage routine combines the effects of the fg_revimage and
  750. fg_clpimage routines -- it displays a reversed image with respect to the
  751. current clipping limits.  Fg_flpimage takes the same three arguments as
  752. fg_drwimage, and also displays the image such that its lower left corner is
  753. at the graphics cursor position.  Like the fg_clpimage routine, fg_flpimage
  754. has no effect when used in a text video mode.  Refer to pages 149 and 151 for
  755. example programs that use fg_flpimage.
  756.  
  757.  
  758. Some Examples
  759.  
  760.      Example 9-8 illustrates the use of the fg_drwimage, fg_clpimage,
  761. fg_revimage, and fg_flpimage routines in the standard CGA four-color graphics
  762. mode (mode 4).  The program uses each of these routines to display a small
  763. white arrow, as shown in the pixel map below.
  764.  
  765.                              . . . . . . * . . .
  766.                              . . . . . . * * . .
  767.                              * * * * * * * * * .
  768.                              * * * * * * * * * *
  769.                              * * * * * * * * * .
  770.                              . . . . . . * * . .
  771.                              . . . . . . * . . .
  772.  
  773. As before, we must first convert this image to a bit map.  The image is ten
  774. pixels wide and seven high.  In mode 4, each pixel occupies two bits, so we
  775. need a 21-byte array (7 rows by 3 columns) to store the image.  Since we want
  776. to make the arrow white, each pixel will be displayed in color 3 (11 binary).
  777. Here is the bit map and its hexadecimal equivalent for the arrow image in
  778. mode 4 (the actual image is in boldface).
  779.  
  780.          00 00 00 00   00 00 11 00   00 00 00 00         00   0C   00
  781.          00 00 00 00   00 00 11 11   00 00 00 00         00   0F   00
  782.          11 11 11 11   11 11 11 11   11 00 00 00         FF   FF   C0
  783.          11 11 11 11   11 11 11 11   11 11 00 00         FF   FF   F0
  784.          11 11 11 11   11 11 11 11   11 00 00 00         FF   FF   C0
  785.          00 00 00 00   00 00 11 11   00 00 00 00         00   0F   00
  786.          00 00 00 00   00 00 11 00   00 00 00 00         00   0C   00
  787.  
  788. 150  Fastgraph User's Guide
  789.  
  790.  
  791.      After establishing the video mode, the program defines the clipping
  792. region.  It then uses fg_drwimage to display the arrow pointing to the right
  793. and fg_clpimage to do the same thing, but with respect to the clipping
  794. limits.  Because the left edge of the arrow is displayed at x=10 and the
  795. right clipping limit is at x=15, the call to fg_clpimage only draws the first
  796. six columns of the arrow (that is, it does not draw the arrow head).
  797.  
  798.      Next, example 9-8 uses fg_revimage to display the arrow pointing to the
  799. left.  To allow for the filler pixels, we must establish the graphics cursor
  800. position two pixels to the left of the position used by fg_drwimage if we
  801. want the tip of the left-pointing arrow to align with the tail of the right-
  802. pointing arrow.  Finally, the program uses fg_flpimage to display an arrow
  803. pointing to the left with regard to the clipping limits.  The call to
  804. fg_flpimage displays the arrow head and the first two columns of the arrow
  805. shaft.
  806.  
  807.                                  Example 9-8.
  808.  
  809.               #include <fastgraf.h>
  810.               #include <stdio.h>
  811.               #include <stdlib.h>
  812.               void main(void);
  813.  
  814.               char arrow[] = {
  815.                  0x00,0x0C,0x00, 0x00,0x0F,0x00, 0xFF,0xFF,0xC0,
  816.                  0xFF,0xFF,0xF0, 0xFF,0xFF,0xC0, 0x00,0x0F,0x00,
  817.                  0x00,0x0C,0x00
  818.                  };
  819.  
  820.               void main()
  821.               {
  822.                  int old_mode;
  823.  
  824.                  if (fg_testmode(4,1) == 0) {
  825.                     printf("This program requires a 320 ");
  826.                     printf("x 200 CGA graphics mode.\n");
  827.                     exit(1);
  828.                     }
  829.  
  830.                  old_mode = fg_getmode();
  831.                  fg_setmode(4);
  832.                  fg_setclip(0,15,0,199);
  833.  
  834.                  fg_move(10,10);
  835.                  fg_drwimage(arrow,3,7);
  836.                  fg_move(10,20);
  837.                  fg_clpimage(arrow,3,7);
  838.                  fg_move(8,30);
  839.                  fg_revimage(arrow,3,7);
  840.                  fg_move(8,40);
  841.                  fg_flpimage(arrow,3,7);
  842.                  fg_waitkey();
  843.                  fg_setmode(old_mode);
  844.                  fg_reset();
  845.               }
  846.  
  847.                                   Chapter 9:  Images and Image Management  151
  848.  
  849.      Example 9-9 is the same as example 9-8, but it uses the low resolution
  850. EGA graphics mode (mode 13).  If we changed the mode number specified in the
  851. calls to fg_testmode and fg_setmode, the program also would run in any native
  852. EGA or VGA graphics mode, or in the Tandy/PCjr 16-color graphics mode.  In
  853. these modes, we store two pixels per byte in the bit map array, so we need a
  854. 35-byte array (7 rows by 5 columns) to store the image.  Here is the bit
  855. map's hexadecimal equivalent for the arrow image in mode 13, followed by the
  856. program to display it.
  857.  
  858.                             00   00   00   F0   00
  859.                             00   00   00   FF   00
  860.                             FF   FF   FF   FF   F0
  861.                             FF   FF   FF   FF   FF
  862.                             FF   FF   FF   FF   F0
  863.                             00   00   00   FF   00
  864.                             00   00   00   F0   00
  865.  
  866.  
  867.                                  Example 9-9.
  868.  
  869.                 #include <fastgraf.h>
  870.                 #include <stdio.h>
  871.                 #include <stdlib.h>
  872.                 void main(void);
  873.  
  874.                 char arrow[] = {
  875.                    0x00,0x00,0x00,0xF0,0x00,
  876.                    0x00,0x00,0x00,0xFF,0x00,
  877.                    0xFF,0xFF,0xFF,0xFF,0xF0,
  878.                    0xFF,0xFF,0xFF,0xFF,0xFF,
  879.                    0xFF,0xFF,0xFF,0xFF,0xF0,
  880.                    0x00,0x00,0x00,0xFF,0x00,
  881.                    0x00,0x00,0x00,0xF0,0x00
  882.                    };
  883.  
  884.                 void main()
  885.                 {
  886.                    int old_mode;
  887.  
  888.                    if (fg_testmode(13,1) == 0) {
  889.                       printf("This program requires a 320 ");
  890.                       printf("x 200 EGA graphics mode.\n");
  891.                       exit(1);
  892.                       }
  893.  
  894. 152  Fastgraph User's Guide
  895.  
  896.                    old_mode = fg_getmode();
  897.                    fg_setmode(13);
  898.                    fg_setclip(0,15,0,199);
  899.  
  900.                    fg_move(10,10);
  901.                    fg_drwimage(arrow,5,7);
  902.                    fg_move(10,20);
  903.                    fg_clpimage(arrow,5,7);
  904.                    fg_move(8,30);
  905.                    fg_revimage(arrow,5,7);
  906.                    fg_move(8,40);
  907.                    fg_flpimage(arrow,5,7);
  908.                    fg_waitkey();
  909.  
  910.                    fg_setmode(old_mode);
  911.                    fg_reset();
  912.                 }
  913.  
  914.  
  915. Pixel Run Maps
  916.  
  917.      The bit maps used with the fg_drawmap, fg_drwimage, and related routines
  918. can consume array space quite rapidly.  This is especially true if the image
  919. is large or contains many colors.  For example, a mode-independent bit-mapped
  920. image that occupies the entire screen in a 320 by 200 graphics mode requires
  921. 8,000 bytes of space per color.  Fastgraph provides another mode-independent
  922. image format called pixel run maps, which are more efficient in terms of
  923. space.  In pixel run maps, you store the entire image in a single array.
  924. Pixel run maps are particularly useful for displaying static images such as
  925. backgrounds.
  926.  
  927.      Let's return to our familiar triangle example and show how we could use
  928. a pixel run map to display it.
  929.  
  930.                               . . . . * . . . .
  931.                               . . . * x * . . .
  932.                               . . * x x x * . .
  933.                               . * x x x x x * .
  934.                               * * * * * * * * *
  935.  
  936. As before, the pixels indicated by an asterisk (*) are the triangle's
  937. perimeter, while those indicated by an x represent its interior points.  The
  938. pixels shown as periods (.) are not part of the triangle itself, but they are
  939. part of the pixel run map.
  940.  
  941.      If we start at the lower left corner of the image and proceed to the
  942. right, we could represent the first row of the image as nine pixels of color
  943. "asterisk".  Such a group of consecutive identically colored pixels is called
  944. a pixel run, so a single pixel run describes the first row of the image.  The
  945. row above this one is a bit more complex.  It consists of five pixel runs:
  946. one pixel of color "period", followed by one of color "asterisk", then five
  947. of color "x", one of color "asterisk", and finally one of color "period".
  948.  
  949.      While we could construct separate pixel runs for each row of the image,
  950. notice that three of the five rows in our triangle begin with the same color
  951. pixel as the rightmost pixel in the previous row.  Fastgraph's pixel run map
  952. format lets you take advantage of this property by allowing pixel runs to
  953.                                   Chapter 9:  Images and Image Management  153
  954.  
  955. wrap from one row to the next.  This means we can represent the pixel run of
  956. color "period" extending from the right side of the second row to the left
  957. side of the third row as a single run of three pixels.
  958.  
  959.      The Fastgraph routine fg_display displays an image stored as a pixel run
  960. map.  The fg_display routine expects three arguments.  The first is an array
  961. containing the pixel runs (passed by reference), the second is the number of
  962. pixel runs in the array, and the third is the width in pixels of the image.
  963. As with the other image display routines, the fg_display routine displays the
  964. image such that its lower left corner is at the graphics cursor position on
  965. the active video page.  The pixel run array is of the following format:
  966.  
  967.                              [0]   color for run 1
  968.  
  969.                              [1]   count for run 1
  970.  
  971.                              [2]   color for run 2
  972.  
  973.                              [3]   count for run 2
  974.                                           .
  975.                                           .
  976.                                           .
  977.                           [2n-2]   color for run n
  978.  
  979.                           [2n-1]   count for run n
  980.  
  981. Each color is a value between 0 and 255 specifying the color index for that
  982. pixel run.  Each count is a value between 0 and 255 specifying the length in
  983. pixels of that pixel run.  If a run is longer than 255 pixels, it must be
  984. broken into two or more runs.  For example, we could represent a pixel run of
  985. length 265 as a run of length 255 followed by a run of length 10 of the same
  986. color.  Note also the array space in bytes needed to store a pixel run map is
  987. twice the number of runs.
  988.  
  989.      It requires 16 pixel runs to store our triangle image as a pixel run
  990. map.  If we want to display the perimeter pixels in color 1, the interior
  991. pixels in color 2, and the filler area in color 7, the pixel run map would
  992. contain 16 sets of (color,count) pairs:  (1,9), (7,1), (1,1), (2,5), (1,1),
  993. (7,3), (1,1), (2,3), (1,1), (7,5), (1,1), (2,1), (1,1), (7,7), (1,1), and
  994. (7,4).
  995.  
  996.      Example 9-10 uses the fg_display routine to display the triangle as a
  997. pixel run map in a 320 by 200 graphics mode.  The program displays the
  998. triangle against a background of color 7, so the selection of color 7 for the
  999. filler area was important.  If some other color were chosen, the filler area
  1000. would not blend in with the background.
  1001.  
  1002.                                 Example 9-10.
  1003.  
  1004.                 #include <fastgraf.h>
  1005.                 #include <stdio.h>
  1006.                 #include <stdlib.h>
  1007.                 void main(void);
  1008.  
  1009. 154  Fastgraph User's Guide
  1010.  
  1011.                 char triangle[] = {
  1012.                    1,9, 7,1, 1,1, 2,5, 1,1, 7,3, 1,1, 2,3,
  1013.                    1,1, 7,5, 1,1, 2,1, 1,1, 7,7, 1,1, 7,4
  1014.                    };
  1015.  
  1016.                 void main()
  1017.                 {
  1018.                    int old_mode, new_mode;
  1019.  
  1020.                    new_mode = fg_bestmode(320,200,1);
  1021.                    if (new_mode < 0 || new_mode == 12) {
  1022.                       printf("This program requires a 320 ");
  1023.                       printf("x 200 color graphics mode.\n");
  1024.                       exit(1);
  1025.                       }
  1026.  
  1027.                    old_mode = fg_getmode();
  1028.                    fg_setmode(new_mode);
  1029.  
  1030.                    fg_setcolor(7);
  1031.                    fg_rect(0,319,0,199);
  1032.  
  1033.                    fg_move(156,101);
  1034.                    fg_display(triangle,16,9);
  1035.                    fg_waitkey();
  1036.  
  1037.                    fg_setmode(old_mode);
  1038.                    fg_reset();
  1039.                 }
  1040.  
  1041.      If you have a pixel run map that only uses the first 16 color indices (0
  1042. to 15), you can use Fastgraph's packed pixel run map image format.  This
  1043. format packs two color values into each color byte and thus needs 25% less
  1044. array space to store an image.  The Fastgraph routine fg_displayp displays an
  1045. image stored as a packed pixel run map.  It is the same as the fg_display
  1046. routine except for the structure of the pixel run array.  Like fg_display,
  1047. the pixel run array used with fg_displayp is a list of pixel runs, but two
  1048. runs are packed into three bytes.  In each such set of three bytes, the high
  1049. four bits of the first byte contain the color of the first run, and the low
  1050. four bits contain the color of the second run.  The second byte contains the
  1051. length of the first run, and the third byte contains the length of the second
  1052. run.
  1053.  
  1054.      The following diagram illustrates the format of the pixel run array used
  1055. with the fg_displayp routine.  The image is assumed to contain n pixel runs,
  1056. where n is an even number.  If n is odd, the index of the last element is
  1057. 3n/2 (truncated) instead of 3n/2-1, and the low four bits of the last color
  1058. byte (that is, the color for pixel run n+1) are ignored.
  1059.  
  1060.                         7                4   3                0
  1061.  
  1062.                    [0]    color for run 1     color for run 2
  1063.  
  1064.                    [1]              count for run 1
  1065.  
  1066.                    [2]              count for run 2
  1067.  
  1068.                                   Chapter 9:  Images and Image Management  155
  1069.  
  1070.  
  1071.                    [3]    color for run 3     color for run 4
  1072.  
  1073.                    [4]              count for run 3
  1074.  
  1075.                    [5]              count for run 4
  1076.                                            .
  1077.                                            .
  1078.                                            .
  1079.               [3n/2-3]   color for run n-1    color for run n
  1080.  
  1081.               [3n/2-2]             count for run n-1
  1082.  
  1083.               [3n/2-1]              count for run n
  1084.  
  1085.      The structure of the packed pixel run array allows for color values to
  1086. be between 0 and 15, and pixel run lengths to be between 0 and 255.  The
  1087. array space in bytes needed to store a packed pixel run map is 1.5 times the
  1088. number of runs, compared to twice the number of runs for the standard pixel
  1089. run format.
  1090.  
  1091.      Example 9-11 is the same as example 9-10, but it uses fg_displayp rather
  1092. than fg_display to display the image.  Note the use of hexadecimal numbers
  1093. for defining the packed color values, which of course is not necessary but
  1094. certainly easier to read than expressing the quantities as decimal numbers.
  1095.  
  1096.                                 Example 9-11.
  1097.  
  1098.                 #include <fastgraf.h>
  1099.                 #include <stdio.h>
  1100.                 #include <stdlib.h>
  1101.                 void main(void);
  1102.  
  1103.                 char triangle[] = {
  1104.                    0x17,9,1, 0x12,1,5, 0x17,1,3, 0x12,1,3,
  1105.                    0x17,1,5, 0x12,1,1, 0x17,1,7, 0x17,1,4
  1106.                    };
  1107.  
  1108.                 void main()
  1109.                 {
  1110.                    int old_mode, new_mode;
  1111.  
  1112.                    new_mode = fg_bestmode(320,200,1);
  1113.                    if (new_mode < 0 || new_mode == 12) {
  1114.                       printf("This program requires a 320 ");
  1115.                       printf("x 200 color graphics mode.\n");
  1116.                       exit(1);
  1117.                       }
  1118.  
  1119.                    old_mode = fg_getmode();
  1120.                    fg_setmode(new_mode);
  1121.  
  1122.                    fg_setcolor(7);
  1123.                    fg_rect(0,319,0,199);
  1124.  
  1125.                    fg_move(156,101);
  1126.  
  1127. 156  Fastgraph User's Guide
  1128.  
  1129.                    fg_displayp(triangle,16,9);
  1130.                    fg_waitkey();
  1131.  
  1132.                    fg_setmode(old_mode);
  1133.                    fg_reset();
  1134.                 }
  1135.  
  1136.      Both the fg_display and fg_displayp routines require the pixel run image
  1137. to be stored in an array.  In examples 9-10 and 9-11, the image is defined
  1138. within the program itself.  However, if the image is stored in a file, it
  1139. must first be read into the pixel run array.  Example 9-12 demonstrates this
  1140. procedure.  The program displays two images stored in files, one in standard
  1141. pixel run format and the other in packed pixel run format.  Each image is a
  1142. picture of the sea floor and some coral, as might be used for the background
  1143. in an aquarium.  The program runs in a 320 by 200 graphics mode, and the
  1144. image fills the entire screen.  It is assumed the image files contain the
  1145. list of pixel runs as a single byte stream that does not include embedded
  1146. characters such as carriage returns or line feeds.
  1147.  
  1148.      The first image, in standard pixel run format, is in the file coral.spr.
  1149. Note the program must open the file for reading in binary mode ("rb" in the
  1150. call to fopen).  The program reads the file's entire contents into the
  1151. pixel_runs array, whose size must be at least as large as the file size.
  1152. Because the image is stored in standard pixel run format, the number of pixel
  1153. runs is one-half the file size.  The program then uses the fg_move routine to
  1154. establish the lower left corner of the screen as the graphics cursor position
  1155. and then calls fg_display to display the image.  As mentioned earlier, the
  1156. image fills the entire screen, so its width is 320 pixels.
  1157.  
  1158.      After waiting for a keystroke, the program similarly displays the second
  1159. image.  This image is in the file coral.ppr and is stored in packed pixel run
  1160. format.  Because the image is packed, the number of pixel runs is two-thirds
  1161. the file size.  The program then clears the previous image from the screen
  1162. and calls fg_displayp to display the image.  After another keystroke, the
  1163. program restores the original video mode and screen attributes and returns to
  1164. DOS.
  1165.  
  1166.                                 Example 9-12.
  1167.  
  1168.              #include <fastgraf.h>
  1169.              #include <io.h>
  1170.              #include <stdio.h>
  1171.              #include <stdlib.h>
  1172.              void main(void);
  1173.  
  1174.              char pixel_runs[20000];
  1175.  
  1176.              void main()
  1177.              {
  1178.                 long filelength();
  1179.                 FILE *stream;
  1180.                 int file_size, run_count;
  1181.                 int old_mode, new_mode;
  1182.  
  1183.                 new_mode = fg_bestmode(320,200,1);
  1184.                 if (new_mode < 0 || new_mode == 12) {
  1185.  
  1186.                                   Chapter 9:  Images and Image Management  157
  1187.  
  1188.                    printf("This program requires a 320 ");
  1189.                    printf("x 200 color graphics mode.\n");
  1190.                    exit(1);
  1191.                    }
  1192.                 old_mode = fg_getmode();
  1193.                 fg_setmode(new_mode);
  1194.  
  1195.                 stream = fopen("coral.spr","rb");
  1196.                 file_size = (int)(filelength(fileno(stream)));
  1197.                 fread(pixel_runs,sizeof(char),file_size,stream);
  1198.                 fclose(stream);
  1199.                 run_count = file_size / 2;
  1200.                 fg_move(0,199);
  1201.                 fg_display(pixel_runs,run_count,320);
  1202.                 fg_waitkey();
  1203.  
  1204.                 stream = fopen("coral.ppr","rb");
  1205.                 file_size = (int)(filelength(fileno(stream)));
  1206.                 fread(pixel_runs,sizeof(char),file_size,stream);
  1207.                 fclose(stream);
  1208.                 run_count = file_size / 3 * 2;
  1209.                 fg_erase();
  1210.                 fg_displayp(pixel_runs,run_count,320);
  1211.                 fg_waitkey();
  1212.  
  1213.                 fg_setmode(old_mode);
  1214.                 fg_reset();
  1215.              }
  1216.  
  1217.      Another Fastgraph routine, fg_dispfile, displays an image directly from
  1218. a file.  This eliminates the need to read the file contents into an array
  1219. before displaying the image, and it also eliminates the need to compute the
  1220. number of pixel runs in the image.  The fg_dispfile routine can display
  1221. images stored in either standard or packed pixel run images.  The first of
  1222. its three arguments is the name of the file containing the image (it may
  1223. include a path name).  The file name must be terminated with a null
  1224. character, so QuickBASIC, FORTRAN, and Turbo Pascal programmers will need to
  1225. store a zero byte as the last character of the file name string.  The second
  1226. argument is the width in pixels of the image, and the third argument defines
  1227. the image format (that is, standard or packed).  As with fg_display and
  1228. fg_displayp, the fg_dispfile routine displays the image such that its lower
  1229. left corner is at the graphics cursor position.
  1230.  
  1231.      Example 9-13 illustrates how to use the fg_dispfile routine to display
  1232. an image stored in a pixel run file.  It is functionally identical to example
  1233. 9-12, but it is much simpler because it uses fg_dispfile instead of fg_display
  1234. and fg_displayp to display the images.  The value of fg_dispfile's third
  1235. argument tells Fastgraph the image format.  A value of 0 indicates the file
  1236. contains an image in standard pixel run format, while a value of 1 indicates
  1237. an image in packed pixel run format.  As in example 9-12, the image files are
  1238. assumed to contain the list of pixel runs as a single byte stream that does
  1239. not include embedded characters such as carriage returns or line feeds.
  1240.  
  1241.                                 Example 9-13.
  1242.  
  1243.                 #include <fastgraf.h>
  1244.  
  1245. 158  Fastgraph User's Guide
  1246.  
  1247.                 #include <stdio.h>
  1248.                 #include <stdlib.h>
  1249.                 void main(void);
  1250.  
  1251.                 void main()
  1252.                 {
  1253.                    int old_mode, new_mode;
  1254.  
  1255.                    new_mode = fg_bestmode(320,200,1);
  1256.                    if (new_mode < 0 || new_mode == 12) {
  1257.                       printf("This program requires a 320 ");
  1258.                       printf("x 200 color graphics mode.\n");
  1259.                       exit(1);
  1260.                       }
  1261.  
  1262.                    old_mode = fg_getmode();
  1263.                    fg_setmode(new_mode);
  1264.  
  1265.                    fg_move(0,199);
  1266.                    fg_dispfile("coral.spr",320,0);
  1267.                    fg_waitkey();
  1268.  
  1269.                    fg_erase();
  1270.                    fg_dispfile("coral.ppr",320,1);
  1271.                    fg_waitkey();
  1272.  
  1273.                    fg_setmode(old_mode);
  1274.                    fg_reset();
  1275.                 }
  1276.  
  1277.  
  1278.      To display the image, the fg_dispfile routine tries to allocate enough
  1279. dynamic memory to read the entire file.  If it is unable to do so, it
  1280. allocates the available memory and displays the image in more than one pass.
  1281. In either case, Fastgraph deallocates the memory after fg_dispfile displays
  1282. the image.
  1283.  
  1284.      The SNAPSHOT utility distributed with Fastgraph is a terminate and stay
  1285. resident program (TSR) that can capture graphics mode screen images and save
  1286. them in standard pixel run files.  Thus, you can easily create files with
  1287. SNAPSHOT and display them with the fg_dispfile routine.  Another TSR utility,
  1288. GrabRGB, is useful for capturing RGB color values from 256-color images.
  1289. Appendix A contains complete descriptions of the SNAPSHOT and GrabRGB
  1290. utilities.
  1291.  
  1292.  
  1293. Display Patterns
  1294.  
  1295.      Examples 9-11, 9-12, and 9-13 work well in the graphics video modes with
  1296. 16 or 256 available colors.  However, in the four-color CGA graphics modes
  1297. the resulting image is not too good because of our limited color choices, and
  1298. it would look even worse in the Hercules graphics mode.  The Fastgraph
  1299. routine fg_pattern allows you to associate a dither pattern (actually, any
  1300. pixel sequence) with one of Fastgraph's 256 color indices appearing in a
  1301. pixel run map.  When displaying a pixel run map (with fg_display,
  1302. fg_displayp, or fg_dispfile), Fastgraph will use the pattern associated with
  1303. that color index instead of displaying the color itself.
  1304.                                   Chapter 9:  Images and Image Management  159
  1305.  
  1306.      The fg_pattern routine requires two integer arguments -- a color index
  1307. (between 0 and 255) and the display pattern defined for that color index.  A
  1308. display pattern's structure resembles the structure of video memory and is
  1309. thus dependent on the current video mode.  The following sections list the
  1310. initial display patterns and explain how to construct new display patterns
  1311. for different graphics video modes.
  1312.  
  1313. CGA four-color graphics modes
  1314.  
  1315.      In the four-color CGA graphics modes (modes 4 and 5), the display
  1316. pattern is a 16-bit quantity consisting of an 8-bit shift count followed by
  1317. an 8-bit pixel pattern.  Each pixel assumes a value between 0 and 3, so the
  1318. pattern represents four pixels.  In even-numbered pixel rows, Fastgraph uses
  1319. the pixel pattern itself.  In odd-numbered pixel rows, Fastgraph rotates the
  1320. original pattern to the left by the number of bits specified by the shift
  1321. count.
  1322.  
  1323.      For example, if we are using the default CGA color palette, we could
  1324. create a lighter shade of cyan by alternating cyan pixels (color 1, 01
  1325. binary) with white pixels (color 3, 11 binary), as shown below.
  1326.  
  1327.                                  01 11 01 11
  1328.  
  1329. If we convert this pixel pattern to its hexadecimal equivalent, we get the
  1330. value 77.
  1331.  
  1332.      To complete the display pattern, we need to determine the shift count.
  1333. If we use a shift count of zero, the resulting display will simply be a
  1334. series of cyan and white vertical lines.  What we really need is a
  1335. checkerboard effect where a white pixel is above and below each cyan pixel,
  1336. and vice versa.  If we rotate the pattern one pixel (two bits) to the left,
  1337. we will achieve the desired effect.  That is, a shift count of two produces
  1338. the following pixel patterns:
  1339.  
  1340.                        even-numbered rows   01 11 01 11
  1341.                         odd-numbered rows   11 01 11 01
  1342.  
  1343. Combining the shift count with the pixel pattern yields the display pattern
  1344. 0277 hex.  The shift count is normally a multiple of two; note that a zero
  1345. shift count results in the same pattern being applied to all pixel rows.
  1346.  
  1347.      For the CGA four-color graphics modes, the fg_setmode routine
  1348. establishes the following initial display patterns:
  1349.  
  1350.                        color  shift count  hexadecimal
  1351.                        index  and pattern  equivalent
  1352.  
  1353.                          0    0 00000000   0000
  1354.                          1    0 01010101   0055
  1355.                          2    0 10101010   00AA
  1356.                          3    0 11111111   00FF
  1357.  
  1358. 160  Fastgraph User's Guide
  1359.  
  1360. These values are repeated as necessary to define color indices 4 to 255.
  1361. That is, colors 4, 8, 12, ... , 252 use the same defaults as color 0.  Colors
  1362. 5, 9, 13, ... , 253 use the same defaults as color 1, and so forth.  Also
  1363. note that pattern 0000 represents four pixels of color 0, 0055 represents
  1364. four pixels of color 1, 00AA represents four pixels of color 2, and 00FF
  1365. represents four pixels of color 3.
  1366.  
  1367. CGA two-color graphics mode
  1368.  
  1369.      In the two-color CGA graphics mode (mode 6), the display pattern is also
  1370. a 16-bit quantity consisting of an 8-bit shift count followed by an 8-bit
  1371. pixel pattern.  Each pixel assumes the value 0 or 1, so the pattern
  1372. represents eight pixels.  In even-numbered pixel rows, Fastgraph uses the
  1373. pixel pattern itself.  In odd-numbered pixel rows, Fastgraph rotates the
  1374. original pattern to the left by the number of bits specified by the shift
  1375. count.
  1376.  
  1377.      For example, we could create a lighter shade of white by alternating
  1378. black pixels (color 0) with white pixels (color 1), as shown below.
  1379.  
  1380.                                0 1 0 1 0 1 0 1
  1381.  
  1382. If we convert this pixel pattern to its hexadecimal equivalent, we get the
  1383. value 55.
  1384.  
  1385.      To complete the display pattern, we need to determine the shift count.
  1386. We must rotate the pattern one pixel (one bit) to the left to achieve the
  1387. checkerboard effect as in the CGA four color graphics modes.  That is, a
  1388. shift count of one produces the following pixel patterns:
  1389.  
  1390.                      even-numbered rows   0 1 0 1 0 1 0 1
  1391.                       odd-numbered rows   1 0 1 0 1 0 1 0
  1392.  
  1393. Combining the shift count with the pixel pattern yields the display pattern
  1394. 0155 hex.
  1395.  
  1396.      For the CGA two-color graphics mode, the fg_setmode routine establishes
  1397. the initial display patterns such that all even-numbered color indices are
  1398. assigned the value 0000, while all odd-numbered color indices are assigned
  1399. the value 00FF.  Note that pattern 0000 represents eight pixels of color 0,
  1400. and 00FF represents eight pixels of color 1.
  1401.  
  1402. Tandy/PCjr 16-color graphics mode
  1403.  
  1404.      In the Tandy/PCjr 16-color graphics mode (mode 9), the display pattern
  1405. is also 16-bit quantity consisting of an 8-bit shift count followed by an 8-
  1406. bit pixel pattern.  Each pixel assumes a value between 0 and 15, so the
  1407. pattern represents two pixels.  In even-numbered pixel rows, Fastgraph uses
  1408. the pixel pattern itself.  In odd-numbered pixel rows, Fastgraph rotates the
  1409. original pattern to the left by the number of bits specified by the shift
  1410. count.
  1411.  
  1412.      For example, we could create a lighter shade of blue by alternating blue
  1413. pixels (color 1, 0001 binary) with white pixels (color 15, 1111 binary), as
  1414. shown below.
  1415.                                   Chapter 9:  Images and Image Management  161
  1416.  
  1417.                                   0001 1111
  1418.  
  1419. If we convert this pixel pattern to its hexadecimal equivalent, we get the
  1420. value 1F.
  1421.  
  1422.      To complete the display pattern, we need to determine the shift count.
  1423. Using the same process as in the CGA graphics modes, we must rotate the
  1424. pattern one pixel (four bits) to the left to achieve the checkerboard effect.
  1425. That is, a shift count of four produces the following pixel patterns:
  1426.  
  1427.                         even-numbered rows   0001 1111
  1428.                          odd-numbered rows   1111 0001
  1429.  
  1430. Combining the shift count with the pixel pattern yields the display pattern
  1431. 041F hex.  The shift count is normally zero or four; note that a zero shift
  1432. count results in the same pattern being applied to all pixel rows.
  1433.  
  1434.      For the Tandy/PCjr 16-color graphics modes, the fg_setmode routine
  1435. establishes the initial display patterns such that color 0 is assigned the
  1436. value 0000 (two pixels of color 0), color 1 is assigned the value 0011 (two
  1437. pixels of color 1), color 2 is assigned the value 0022 (two pixels of color
  1438. 2), and so forth.  These values are repeated as necessary to define color
  1439. indices 16 to 255.  That is, colors 0, 16, 32, ... , 240 use the same
  1440. defaults as color 0.  Colors 1, 17, 33, ... , 241 use the same defaults as
  1441. color 1, and so forth.
  1442.  
  1443. Hercules graphics modes
  1444.  
  1445.      The structure of the display patterns for the Hercules graphics modes
  1446. (modes 11 and 12) is the same as two of the CGA graphics modes.  For the
  1447. standard Hercules graphics mode (mode 11), please refer to the discussion of
  1448. CGA two-color (mode 6) display patterns on page 160.  For the low-resolution
  1449. Hercules graphics mode (mode 12), please refer to the discussion of the CGA
  1450. four-color (mode 4) display patterns on page 159.
  1451.  
  1452. EGA graphics modes
  1453.  
  1454.      In the EGA graphics modes (modes 13 to 16), the display pattern is an 8-
  1455. bit quantity consisting of two 4-bit color values (for consistency with the
  1456. other video modes, we still pass the display pattern as a 16-bit quantity).
  1457. Each pixel assumes a value between 0 and 15 (0 and 5 in the EGA monochrome
  1458. graphics mode), so the pattern represents two pixels.  In even-numbered pixel
  1459. rows, Fastgraph uses the pixel pattern itself.  In odd-numbered pixel rows,
  1460. Fastgraph rotates the original pattern one pixel (four bits) to the left.
  1461.  
  1462.      For example, we could create a lighter shade of blue by alternating blue
  1463. pixels (color 1, 0001 binary) with white pixels (color 15, 1111 binary), as
  1464. shown below.
  1465.  
  1466.                                   0001 1111
  1467.  
  1468. If we convert this pixel pattern to its hexadecimal equivalent, we get the
  1469. value 1F.  The implied four-bit shift count produces the following pixel
  1470. patterns:
  1471. 162  Fastgraph User's Guide
  1472.  
  1473.                         even-numbered rows   0001 1111
  1474.                          odd-numbered rows   1111 0001
  1475.  
  1476. Extending the pixel pattern to a 16-bit quantify yields the display pattern
  1477. 001F hex.
  1478.  
  1479.      For the EGA and VGA 16-color graphics modes, the fg_setmode routine
  1480. establishes the initial display patterns such that color 0 is assigned the
  1481. value 0000 (two pixels of color 0), color 1 is assigned the value 0011 (two
  1482. pixels of color 1), color 2 is assigned the value 0022 (two pixels of color
  1483. 2), and so forth.  These values are repeated as necessary to define color
  1484. indices 16 to 255.  That is, colors 0, 16, 32, ... , 240 use the same
  1485. defaults as color 0.  Colors 1, 17, 33, ... , 241 use the same defaults as
  1486. color 1, and so forth.
  1487.  
  1488. MCGA/VGA 2-color graphics mode
  1489.  
  1490.      In the two-color MCGA/VGA graphics mode (mode 17), the display pattern
  1491. is a 2-bit quantity consisting of two 1-bit color values (for consistency
  1492. with the other video modes, we still pass the display pattern as a 16-bit
  1493. quantity).  Each pixel assumes the value 0 or 1, so the pattern represents
  1494. two pixels.  In even-numbered pixel rows, Fastgraph uses the pixel pattern
  1495. itself.  In odd-numbered pixel rows, Fastgraph rotates the original pattern
  1496. one pixel (one bit) to the left.
  1497.  
  1498.      For example, we could create a lighter shade of white by alternating
  1499. black pixels (color 0) with white pixels (color 1), as shown below.
  1500.  
  1501.                                      0 1
  1502.  
  1503. If we convert this pixel pattern to its hexadecimal equivalent, we get the
  1504. value 01.  The implied one-bit shift count produces the following pixel
  1505. patterns:
  1506.  
  1507.                            even-numbered rows   0 1
  1508.                             odd-numbered rows   1 0
  1509.  
  1510. Extending the pixel pattern to a 16-bit quantity yields the display pattern
  1511. 0001 hex.
  1512.  
  1513.      For the MCGA/VGA two-color graphics mode, the fg_setmode routine
  1514. establishes the initial display patterns such that all even-numbered color
  1515. indices are assigned the value 0000 (two pixels of color 0), while all odd-
  1516. numbered color indices are assigned the value 0003 (11 binary, or two pixels
  1517. of color 1).
  1518.  
  1519. VGA 16-color graphics mode
  1520.  
  1521.      The structure of the display patterns for the VGA 16-color graphics mode
  1522. (mode 18) is the same as that of the EGA graphics modes.  A discussion of EGA
  1523. display patterns appears on page 161.
  1524.                                   Chapter 9:  Images and Image Management  163
  1525.  
  1526. MCGA and VGA 256-color graphics modes
  1527.  
  1528.      The MCGA and VGA 256-color graphics modes (modes 19 through 23) offer
  1529. 262,144 different colors, so dithering is seldom (if ever) required.  For
  1530. this reason, the fg_pattern routine has no effect in these video modes.
  1531.  
  1532. An example
  1533.  
  1534.      Example 9-14 illustrates the use of display patterns in several graphics
  1535. modes.  This program runs in any 320 by 200 color graphics mode and displays
  1536. the coral image in packed pixel run format, as in example 9-13, but it
  1537. redefines one or more of the color indices.  If the program runs in the
  1538. standard CGA four-color mode (mode 4), it redefines the first 16 display
  1539. patterns using the fg_pattern routine and the values in the CGApatterns
  1540. array.  In the Tandy/PCjr 16-color graphics mode (mode 9) and the EGA low-
  1541. resolution graphics mode (mode 13), the program redefines color index 15 to
  1542. produce an alternating gray and bright white dither pattern.  In the MCGA
  1543. 256-color mode (mode 19), display patterns are not available, so the program
  1544. uses fg_setrgb to define color index 15 as slightly darker shade of gray than
  1545. the default for color 7.
  1546.  
  1547.                                 Example 9-14.
  1548.  
  1549.                 #include <fastgraf.h>
  1550.                 #include <stdio.h>
  1551.                 #include <stdlib.h>
  1552.                 void main(void);
  1553.  
  1554.                 int CGApatterns[] = {
  1555.                    0x0000,0x00FF,0x00FF,0x00FF,
  1556.                    0x02BB,0x0000,0x0222,0x0255,
  1557.                    0x00FF,0x00FF,0x00FF,0x0055,
  1558.                    0x00AA,0x00AA,0x00FF,0x0277
  1559.                    };
  1560.  
  1561.                 void main()
  1562.                 {
  1563.                    int color;
  1564.                    int old_mode, new_mode;
  1565.  
  1566.                    new_mode = fg_bestmode(320,200,1);
  1567.                    if (new_mode < 0 || new_mode == 12) {
  1568.                       printf("This program requires a 320 ");
  1569.                       printf("x 200 color graphics mode.\n");
  1570.                       exit(1);
  1571.                       }
  1572.  
  1573.                    old_mode = fg_getmode();
  1574.                    fg_setmode(new_mode);
  1575.  
  1576.                    if (new_mode == 4) {
  1577.                       fg_palette(0,0);
  1578.                       for (color = 0; color < 16; color++)
  1579.                          fg_pattern(color,CGApatterns[color]);
  1580.                       }
  1581.                    else if (new_mode == 9 || new_mode == 13)
  1582.  
  1583. 164  Fastgraph User's Guide
  1584.  
  1585.                       fg_pattern(15,0x04F7);
  1586.                    else
  1587.                       fg_setrgb(15,38,38,38);
  1588.  
  1589.                    fg_move(0,199);
  1590.                    fg_dispfile("coral.ppr",320,1);
  1591.                    fg_waitkey();
  1592.  
  1593.                    fg_setmode(old_mode);
  1594.                    fg_reset();
  1595.                 }
  1596.  
  1597.  
  1598.  
  1599. PCX Images
  1600.  
  1601.      The PCX file format was originally developed by ZSoft Corporation for
  1602. their commercial paint program, PC Paintbrush.  It has evolved into one of
  1603. the more popular image file formats because so many products can read PCX
  1604. files to at least some extent.  Fastgraph includes routines for displaying
  1605. and creating PCX files.
  1606.  
  1607.      The fg_disppcx routine displays an image stored in a PCX file.  It
  1608. positions the image such that its upper left corner is at the graphics cursor
  1609. position on the active video page.  The first argument to fg_disppcx is the
  1610. name of the PCX file (it may include a path name), and its second argument is
  1611. a 16-bit mask that controls how the image is displayed.  The file name must
  1612. be terminated with a null character, so QuickBASIC, FORTRAN, and Turbo Pascal
  1613. programmers will need to store a zero byte as the last character of the file
  1614. name string.  In the current version of Fastgraph, only the low-order bit
  1615. (bit 0) of the bit mask argument is meaningful.  If the bit is set,
  1616. fg_disppcx will use the current palette settings.  If it is zero, fg_disppcx
  1617. will use the palette values stored in the PCX file.  All other bits are
  1618. reserved and should be zero.  The fg_disppcx routine returns a value of 0 if
  1619. successful, 1 if the specified file wasn't found, and 2 if the file is not a
  1620. PCX file.
  1621.  
  1622.      The fg_makepcx routine creates a PCX file from the specified rectangular
  1623. region of the active video page.  Its first four arguments define the minimum
  1624. x, maximum x, minimum y, and maximum y screen space coordinates of the region
  1625. (the minimum x coordinate is reduced to a byte boundary if necessary).  Its
  1626. fifth argument is the name of the PCX file to create (it may include a path
  1627. name).  As with fg_disppcx, the file name must be terminated with a null
  1628. character.  If an identically named file exists, it is overwritten.  The
  1629. fg_makepcx routine returns a value of 0 if successful, and 1 if the PCX file
  1630. was not created.
  1631.  
  1632.      Example 9-15 uses the fg_disppcx and fg_makepcx routines to create a new
  1633. PCX file from selected rows of an existing 256-color 320 x 200 PCX file.  As
  1634. written, the program uses the file CORAL.PCX to create NEW.PCX, but it could
  1635. easily be extended to work with any PCX files.  The call to fg_disppcx
  1636. displays the contents of CORAL.PCX using the palette settings defined in the
  1637. PCX file.  After waiting for a keystroke, the program calls fg_makepcx to
  1638. create a PCX file named NEW.PCX from pixel rows 80 through 99 of the original
  1639. image.  In case the program encounters any problems, it prints an error
  1640. message before exiting.
  1641.                                   Chapter 9:  Images and Image Management  165
  1642.  
  1643.                                 Example 9-15.
  1644.  
  1645.            #include <fastgraf.h>
  1646.            #include <stdio.h>
  1647.            #include <stdlib.h>
  1648.            void main(void);
  1649.  
  1650.            void main()
  1651.            {
  1652.               int old_mode;
  1653.               int read_status, write_status;
  1654.  
  1655.               if (fg_testmode(19,1) == 0) {
  1656.                  printf("This program requires a 320 ");
  1657.                  printf("x 200 MCGA graphics mode.\n");
  1658.                  exit(1);
  1659.                  }
  1660.               old_mode = fg_getmode();
  1661.               fg_setmode(19);
  1662.  
  1663.               read_status = fg_disppcx("coral.pcx",0);
  1664.               fg_waitkey();
  1665.               if (read_status == 0)
  1666.                  write_status = fg_makepcx(0,319,80,99,"new.pcx");
  1667.               else
  1668.                  write_status = 1;
  1669.  
  1670.               fg_setmode(old_mode);
  1671.               fg_reset();
  1672.  
  1673.               if (read_status == 1)
  1674.                  printf("CORAL.PCX not found.\n");
  1675.               else if (read_status == 2)
  1676.                  printf("CORAL.PCX is not a PCX file.\n");
  1677.               if (write_status == 1)
  1678.                  printf("NEW.PCX not created.\n");
  1679.            }
  1680.  
  1681.  
  1682.      Because their structure parallels the structure of video memory, PCX
  1683. files are specific to certain video modes.  The following table summarizes
  1684. the compatible video modes for PCX files.
  1685.  
  1686.                      If PCX file was   You can display
  1687.                      created in mode   it in these modes
  1688.  
  1689.                      4 or 5            4 or 5
  1690.                      6 or 11           6, 11, 13 to 18
  1691.                      9                 9
  1692.                      13 to 18          13 to 18
  1693.                      19                19 to 23
  1694.  
  1695. Displaying a PCX file at a lower resolution (for example, a 640x480 PCX file
  1696. at 320x200) will truncate the display on the right and on the bottom.  This
  1697. effectively displays the upper left corner of the PCX file.  If you try to
  1698. 166  Fastgraph User's Guide
  1699.  
  1700. display a PCX file in an incompatible video mode, fg_disppcx will still
  1701. display something, but it will be garbled.
  1702.  
  1703.      In the Tandy/PCjr 16-color graphics mode (mode 9) and the native EGA
  1704. graphics modes (modes 13 through 16), the palette registers are not readable.
  1705. Hence, fg_makepcx will use the default palette settings when used in these
  1706. video modes.  In 640-column EGA modes, you can get around this problem by
  1707. creating PCX files in mode 18 and only using the first 200 or 350 pixel rows.
  1708. PCX files created in mode 18 preserve the current palette settings and will
  1709. display properly in EGA modes.  The fg_disppcx and fg_makepcx routines have
  1710. no effect in text video modes or in the Hercules low-resolution graphics
  1711. mode.
  1712.  
  1713.  
  1714. Masking Maps
  1715.  
  1716.      It is not possible to include color 0 pixels in an image displayed with
  1717. the fg_drwimage, fg_clpimage, fg_revimage, or fg_flpimage routines.  This is
  1718. because these routines consider color 0 pixels to be transparent, which means
  1719. such pixels do not affect the corresponding pixels in video memory.  There
  1720. are times, however, when you will want color 0 pixels to be destructive, or
  1721. replace the video memory contents.
  1722.  
  1723.      Consider again the arrow image of example 9-8 (see page 149).  In this
  1724. example, we displayed a bright white (color 3) arrow against a black (color
  1725. 0) background in the standard CGA four-color graphics mode.  Suppose, though,
  1726. that we want to do just the opposite -- display a black (color 0) arrow
  1727. against a bright white (color 3) background.  Example 9-9 (see page 151) does
  1728. this in an EGA graphics mode, but how would we display the black arrow in a
  1729. CGA graphics mode?  We could of course use the fg_drawmap routine or one of
  1730. the routines for displaying pixel run maps, but fg_drawmap does not support
  1731. clipping or reversing an image.   There are, however, four Fastgraph routines
  1732. designed just for this purpose.  These routines are fg_drawmask, fg_clipmask,
  1733. fg_revmask, and fg_flipmask.
  1734.  
  1735.      Each of these routines uses a data structure called a masking map.  A
  1736. masking map is similar in structure to a pixel run map, but it does not
  1737. include any information about colors.  Instead, it consists of a series of
  1738. pixel runs that alternate between protected and unprotected pixels.  An
  1739. example might best clarify this.
  1740.  
  1741.      Once again, here is the arrow image of examples 9-8 and 9-9.
  1742.  
  1743.                              . . . . . . * . . .
  1744.                              . . . . . . * * . .
  1745.                              * * * * * * * * * .
  1746.                              * * * * * * * * * *
  1747.                              * * * * * * * * * .
  1748.                              . . . . . . * * . .
  1749.                              . . . . . . * . . .
  1750.  
  1751. This time, though, we want the arrow to appear in color 0.  Put another way,
  1752. we need the "period" pixels (.) to protect video memory, while we want the
  1753. "asterisk" pixels (*) to zero video memory.  Looking at this problem from the
  1754. perspective of a pixel run map, we have an alternating series of "protect"
  1755. and "zero" runs.  We don't need any information about pixel colors, just
  1756. whether to protect or to zero video memory.
  1757.                                   Chapter 9:  Images and Image Management  167
  1758.  
  1759.      This is precisely the structure of a masking map.  Starting from the
  1760. lower left corner of the image and proceeding to the right, wrapping up to
  1761. the next row when needed, we could represent this image as a masking map with
  1762. 6 protected pixels, 1 zeroed pixel, 9 protected pixels, 2 zeroed pixels, and
  1763. so on.  In general, the structure of a masking map is as follows.
  1764.  
  1765.  
  1766.                       [1]   length of 1st protect run
  1767.  
  1768.                       [2]   length of 1st  zero   run
  1769.  
  1770.                       [3]   length of 2nd protect run
  1771.  
  1772.                       [4]   length of 2nd  zero   run
  1773.                                         .
  1774.                                         .
  1775.                                         .
  1776.                     [n-2]   length of final protect run
  1777.  
  1778.                     [n-1]   length of final  zero   run
  1779.  
  1780.  
  1781.      Looking at this diagram, we see that the even-numbered array elements
  1782. hold the length of the "protect" runs, and the odd-numbered elements hold the
  1783. length of the "zero" runs.  If you need the first run to be a "zero" run,
  1784. just include a "protect" run of length zero as the first element of the
  1785. array.  If the final run is a "protect" run, you do not need to include a
  1786. zero-length "zero" run at the end of the array.  Finally, if either type of
  1787. run exceeds 255 pixels, you'll need to split this into two or more pixel
  1788. runs.  In this case, be sure to include a zero-length run of the other type
  1789. between the two array elements.
  1790.  
  1791.      Example 9-16 illustrates the use of a masking map through the
  1792. fg_drawmask, fg_clipmask, fg_revmask, and fg_flipmask routines in the
  1793. standard CGA four-color graphics mode (mode 4) to draw a black (color 0)
  1794. arrow against a bright white background.  These four routines are
  1795. respectively analogous to the fg_drwimage, fg_clpimage, fg_revimage, and
  1796. fg_flpimage routines, but they use masking maps rather than bit maps.  The
  1797. first argument of each routine is the masking map array (passed by
  1798. reference), the second argument is the number of runs (that is, the number of
  1799. elements) in the masking map array, and the third argument is the width in
  1800. pixels of the image.
  1801.  
  1802.                                 Example 9-16.
  1803.  
  1804.                 #include <fastgraf.h>
  1805.                 #include <stdio.h>
  1806.                 #include <stdlib.h>
  1807.                 void main(void);
  1808.  
  1809.                 char arrow[] = {6,1,9,2,2,9,1,19,7,2,8,1};
  1810.  
  1811.                 void main()
  1812.                 {
  1813.                    int old_mode;
  1814.  
  1815. 168  Fastgraph User's Guide
  1816.  
  1817.                    if (fg_testmode(4,1) == 0) {
  1818.                       printf("This program requires a 320 ");
  1819.                       printf("x 200 CGA graphics mode.\n");
  1820.                       exit(1);
  1821.                       }
  1822.                    old_mode = fg_getmode();
  1823.                    fg_setmode(4);
  1824.                    fg_setclip(0,15,0,199);
  1825.  
  1826.                    fg_setcolor(3);
  1827.                    fg_rect(0,319,0,199);
  1828.                    fg_move(10,10);
  1829.                    fg_drawmask(arrow,12,10);
  1830.                    fg_move(10,20);
  1831.                    fg_clipmask(arrow,12,10);
  1832.                    fg_move(10,30);
  1833.                    fg_revmask(arrow,12,10);
  1834.                    fg_move(10,40);
  1835.                    fg_flipmask(arrow,12,10);
  1836.                    fg_waitkey();
  1837.  
  1838.                    fg_setmode(old_mode);
  1839.                    fg_reset();
  1840.                 }
  1841.  
  1842.      One of the more useful features of masking maps is the ability to clear
  1843. a portion of video memory before placing an image there.  This technique
  1844. provides an efficient, simple way to include color 0 pixels in an image.  It
  1845. is especially effective when displaying large or dithered images because the
  1846. masking map is typically much smaller than the bit map required by fg_drawmap
  1847. or its related routines.  Example 9-17 illustrates this process in the
  1848. standard CGA four-color graphics mode (mode 4) by displaying our arrow image
  1849. against a colored background.  In this example, the arrow has a bright white
  1850. (color 3) perimeter and a black (color 0) interior.
  1851.  
  1852.      The program displays the arrow in two steps.  It first uses fg_drawmask
  1853. to clear the video memory where the arrow will be displayed.  It then draws
  1854. the arrow's perimeter using the fg_drwimage routine.  The interior pixels in
  1855. the perimeter bit map are transparent, but since we just zeroed that video
  1856. memory, they appear in color 0.  Note we could improve this example by
  1857. creating a smaller masking map that only applies to the rectangle inscribing
  1858. the arrow's interior.  That is, we don't need to zero the video memory under
  1859. the arrow's perimeter because we will immediately display other pixels there.
  1860.  
  1861.                                 Example 9-17.
  1862.  
  1863.               #include <fastgraf.h>
  1864.               #include <stdio.h>
  1865.               #include <stdlib.h>
  1866.               void main(void);
  1867.  
  1868.               char arrow_white[] = {
  1869.                  0x00,0x0C,0x00, 0x00,0x0F,0x00, 0xFF,0xFC,0xC0,
  1870.                  0xC0,0x00,0x30, 0xFF,0xFC,0xC0, 0x00,0x0F,0x00,
  1871.                  0x00,0x0C,0x00
  1872.                  };
  1873.  
  1874.                                   Chapter 9:  Images and Image Management  169
  1875.  
  1876.               char arrow_black[] = {6,1,9,2,2,9,1,19,7,2,8,1};
  1877.  
  1878.               void main()
  1879.               {
  1880.                  int old_mode;
  1881.  
  1882.                  if (fg_testmode(4,1) == 0) {
  1883.                     printf("This program requires a 320 ");
  1884.                     printf("x 200 CGA graphics mode.\n");
  1885.                     exit(1);
  1886.                     }
  1887.  
  1888.                  old_mode = fg_getmode();
  1889.                  fg_setmode(4);
  1890.  
  1891.                  fg_setcolor(2);
  1892.                  fg_rect(0,319,0,199);
  1893.  
  1894.                  fg_move(10,10);
  1895.                  fg_drawmask(arrow_black,12,10);
  1896.                  fg_drwimage(arrow_white,3,7);
  1897.                  fg_waitkey();
  1898.  
  1899.                  fg_setmode(old_mode);
  1900.                  fg_reset();
  1901.               }
  1902.  
  1903.  
  1904.  
  1905. Retrieving Images
  1906.  
  1907.      Sometimes it is necessary to retrieve an image from video memory and
  1908. store it in one or more bit map arrays.  Fastgraph includes two routines,
  1909. fg_getmap and fg_getimage, for this purpose.  The fg_getmap routine retrieves
  1910. pixels of the current color index and stores them in the mode-independent bit
  1911. map format used by fg_drawmap.  The fg_getimage routine retrieves an image
  1912. and stores it in the mode-specific bit map format used by fg_drwimage,
  1913. fg_clpimage, fg_revimage, and fg_flpimage.  The arguments to fg_getmap and
  1914. fg_getimage are respectively analogous to those of fg_drawmap and
  1915. fg_drwimage:  the first is an array (passed by reference) to receive the bit
  1916. map, the second is the width of the bit map in bytes, and the last is the
  1917. height of the bit map in pixel rows.  With either routine, the graphics
  1918. cursor position on the active video page defines the lower left corner of the
  1919. image to retrieve.
  1920.  
  1921.      If we want to use the fg_getmap routine to retrieve an image containing
  1922. more than one color, we must call the routine once per color.  In this case
  1923. we'll usually want to pass different bit map arrays to fg_getmap (or perhaps
  1924. different offsets into the same array).  This might seem unusual at first,
  1925. but it parallels the behavior of the fg_drawmap routine.  That is, to display
  1926. a multicolor image using fg_drawmap, we must call it once for each color in
  1927. the image.
  1928.  
  1929.      Example 9-18 demonstrates a typical use of the fg_getmap routine.  The
  1930. program displays the word "text" in the upper left corner of the screen using
  1931. a 320 by 200 graphics mode.  It uses fg_getmap to retrieve the word as an
  1932. 170  Fastgraph User's Guide
  1933.  
  1934. image and then displays it in a new position with the fg_drawmap routine.
  1935. Let's look at the program now, and afterward we'll more closely examine the
  1936. screen coordinates and the structure of the bit map array.
  1937.  
  1938.                                 Example 9-18.
  1939.  
  1940.                 #include <fastgraf.h>
  1941.                 #include <stdio.h>
  1942.                 #include <stdlib.h>
  1943.                 void main(void);
  1944.  
  1945.                 void main()
  1946.                 {
  1947.                    char bitmap[32];
  1948.                    int old_mode, new_mode;
  1949.  
  1950.                    new_mode = fg_bestmode(320,200,1);
  1951.                    if (new_mode < 0 || new_mode == 12) {
  1952.                       printf("This program requires a 320 ");
  1953.                       printf("x 200 color graphics mode.\n");
  1954.                       exit(1);
  1955.                       }
  1956.  
  1957.                    old_mode = fg_getmode();
  1958.                    fg_setmode(new_mode);
  1959.  
  1960.                    fg_setcolor(9);
  1961.                    fg_text("text",4);
  1962.                    fg_waitkey();
  1963.  
  1964.                    fg_move(0,7);
  1965.                    fg_getmap(bitmap,4,8);
  1966.                    fg_move(4,15);
  1967.                    fg_drawmap(bitmap,4,8);
  1968.                    fg_waitkey();
  1969.  
  1970.                    fg_setmode(old_mode);
  1971.                    fg_reset();
  1972.                 }
  1973.  
  1974.      In all 320 by 200 graphics video modes, individual characters are 8
  1975. pixels wide and 8 pixels high.  This means the lower left corner of the (0,0)
  1976. character cell is referenced by the screen coordinates (0,7).  Hence, these
  1977. are the coordinates of the first call to fg_move.  The image retrieved in
  1978. example 9-18 is four characters long (32 pixels wide), so we need a bit map
  1979. array capable of holding 8 rows of 32 pixels (4 bytes) each.  Our bit map
  1980. array is therefore a 32-byte array, logically structured to have 4 columns
  1981. and 8 rows.  These values are the width and height arguments passed to
  1982. fg_getmap and fg_drawmap.
  1983.  
  1984.      After it retrieves the image, example 9-18 displays it one line below
  1985. and one-half character cell (four pixels) to the right of its original
  1986. position.  In other words, the program displays the image four pixels to the
  1987. right of the (1,0) character cell.  The lower left corner of that cell is
  1988. referenced by the screen coordinates (0,15), so the image should appear at
  1989. the position (4,15).  These are the coordinates of the second call to
  1990. fg_move.
  1991.                                   Chapter 9:  Images and Image Management  171
  1992.  
  1993.      Example 9-19 illustrates the use of the fg_getmap and fg_drawmap
  1994. routines to retrieve and display two-color image.  This example is similar to
  1995. example 9-18, but this program first draws a rectangle in the upper left
  1996. corner of the screen and then displays the word "text" on top of the
  1997. rectangle in a different color.  Each character in a 320 by 200 graphics
  1998. video mode is 8 pixels wide and 8 pixels high, so the rectangle must be 32
  1999. pixels wide (4 characters times 8 pixels per character) and 8 pixels high.
  2000. The image to retrieve will be the same size as the rectangle.
  2001.  
  2002.      The image retrieved in example 9-18 required a 32-byte array, logically
  2003. structured to have 4 columns and 8 rows.  Example 9-19 will retrieve an image
  2004. of the same structure, but the image contains two colors instead of just one.
  2005. This means we need two 32-byte arrays, one for each color, to hold the image.
  2006. We could instead use a single 64-byte array and pass an offset into that
  2007. array (specifically, &bitmap[32]) for processing the second color.
  2008.  
  2009.                                 Example 9-19.
  2010.  
  2011.                 #include <fastgraf.h>
  2012.                 #include <stdio.h>
  2013.                 #include <stdlib.h>
  2014.                 void main(void);
  2015.  
  2016.                 void main()
  2017.                 {
  2018.                    char bitmap1[32], bitmap2[32];
  2019.                    int old_mode, new_mode;
  2020.  
  2021.                    new_mode = fg_bestmode(320,200,1);
  2022.                    if (new_mode < 0 || new_mode == 12) {
  2023.                       printf("This program requires a 320 ");
  2024.                       printf("x 200 color graphics mode.\n");
  2025.                       exit(1);
  2026.                       }
  2027.  
  2028.                    old_mode = fg_getmode();
  2029.                    fg_setmode(new_mode);
  2030.  
  2031.                    fg_setcolor(7);
  2032.                    fg_rect(0,31,0,7);
  2033.                    fg_setcolor(9);
  2034.                    fg_text("text",4);
  2035.                    fg_waitkey();
  2036.  
  2037.                    fg_move(0,7);
  2038.                    fg_setcolor(7);
  2039.                    fg_getmap(bitmap1,4,8);
  2040.                    fg_setcolor(9);
  2041.                    fg_getmap(bitmap2,4,8);
  2042.  
  2043.                    fg_move(4,15);
  2044.                    fg_setcolor(7);
  2045.                    fg_drawmap(bitmap1,4,8);
  2046.                    fg_setcolor(9);
  2047.                    fg_drawmap(bitmap2,4,8);
  2048.                    fg_waitkey();
  2049.  
  2050. 172  Fastgraph User's Guide
  2051.  
  2052.                    fg_setmode(old_mode);
  2053.                    fg_reset();
  2054.                 }
  2055.  
  2056.      Example 9-20 is similar to example 9-19, but it uses fg_getimage and
  2057. fg_drwimage instead of fg_getmap and fg_drawmap to retrieve and display the
  2058. image.  That is, it uses the mode-specific rather than the mode-independent
  2059. image retrieval and display routines.  When using the mode-specific routines,
  2060. the size of the bit map needed to hold the image depends on the video mode.
  2061. For programs that run in only one video mode, bit map widths are constant,
  2062. but when a program must run in several video modes, the width is variable.
  2063. The Fastgraph routine fg_imagesiz computes the number of bytes required to
  2064. store a mode-specific bit-mapped image of specified dimensions.  Its two
  2065. integer arguments specify the image width and height in pixels.
  2066.  
  2067.      The program computes the image width in bytes by passing a height of 1
  2068. to fg_imagesiz.  The size of the bit map array in example 9-20 is 256 bytes,
  2069. the size required in the MCGA graphics mode (32 bytes times 8 bytes).  The
  2070. other video modes require less storage, so in these modes only a portion of
  2071. the bit map array will actually be used.  The image width is then used in the
  2072. calls to both fg_getimage and fg_drwimage.
  2073.  
  2074.                                 Example 9-20.
  2075.  
  2076.                 #include <fastgraf.h>
  2077.                 #include <stdio.h>
  2078.                 #include <stdlib.h>
  2079.                 void main(void);
  2080.  
  2081.                 void main()
  2082.                 {
  2083.                    char bitmap[256];
  2084.                    int old_mode, new_mode;
  2085.                    int width;
  2086.  
  2087.                    new_mode = fg_bestmode(320,200,1);
  2088.                    if (new_mode < 0 || new_mode == 12) {
  2089.                       printf("This program requires a 320 ");
  2090.                       printf("x 200 color graphics mode.\n");
  2091.                       exit(1);
  2092.                       }
  2093.                    old_mode = fg_getmode();
  2094.                    fg_setmode(new_mode);
  2095.                    width = (int)fg_imagesiz(32,1);
  2096.  
  2097.                    fg_setcolor(7);
  2098.                    fg_rect(0,31,0,7);
  2099.                    fg_setcolor(9);
  2100.                    fg_text("text",4);
  2101.                    fg_waitkey();
  2102.  
  2103.                    fg_move(0,7);
  2104.                    fg_getimage(bitmap,width,8);
  2105.                    fg_move(4,15);
  2106.                    fg_drwimage(bitmap,width,8);
  2107.                    fg_waitkey();
  2108.  
  2109.                                   Chapter 9:  Images and Image Management  173
  2110.  
  2111.                    fg_setmode(old_mode);
  2112.                    fg_reset();
  2113.                 }
  2114.  
  2115. While this example used an array to store the image, it's usually preferable
  2116. to allocate dynamic memory for this purpose.  We could have done this in
  2117. example 9-20 by calling fg_imagesiz with arguments of 32 (width) and 8
  2118. (height).  The routine's return value would then tell us the number of bytes
  2119. we would need to allocate.
  2120.  
  2121.      We also can use the fg_getimage routine to retrieve images in text video
  2122. modes.  In text modes, however, there are a few differences we must consider
  2123. when using fg_getimage.  First, the text cursor position, not the graphics
  2124. cursor position, specifies the lower left corner of the image.  Hence, we
  2125. must use the fg_locate routine instead of fg_move to define the image
  2126. location.  Second, the image width is always twice the number of characters
  2127. per image row (that is, for each character we have a character byte and an
  2128. attribute byte).  The fg_getmap routine has no effect when used in a text
  2129. video mode.
  2130.  
  2131.      Example 9-21 shows a simple use of fg_getimage in text modes.  This
  2132. program is similar to example 9-20, but it runs in an 80-column text mode
  2133. rather than a 320 by 200 graphics mode.  As before, the program will retrieve
  2134. the four characters "text" as an image from the upper left corner of the
  2135. screen and then display it in a different location.  Because the image
  2136. consists of four characters in one row, the image width is 8 bytes and the
  2137. image height is 1.
  2138.  
  2139.                                 Example 9-21.
  2140.  
  2141.                    #include <fastgraf.h>
  2142.                    #include <stdio.h>
  2143.                    #include <stdlib.h>
  2144.                    void main(void);
  2145.  
  2146.                    void main()
  2147.                    {
  2148.                       int old_mode;
  2149.                       char image[8];
  2150.  
  2151.                       old_mode = fg_getmode();
  2152.  
  2153.                       if (fg_testmode(3,1))
  2154.                          fg_setmode(3);
  2155.                       else if (fg_testmode(7,1))
  2156.                          fg_setmode(7);
  2157.                       else {
  2158.                          printf("This program requires\n");
  2159.                          printf("an 80-column display.\n");
  2160.                          exit(1);
  2161.                          }
  2162.  
  2163.                       fg_cursor(0);
  2164.  
  2165.                       fg_setattr(9,7,0);
  2166.                       fg_text("text",4);
  2167.  
  2168. 174  Fastgraph User's Guide
  2169.  
  2170.                       fg_waitkey();
  2171.  
  2172.                       fg_locate(0,0);
  2173.                       fg_getimage(image,8,1);
  2174.                       fg_locate(1,1);
  2175.                       fg_drwimage(image,8,1);
  2176.                       fg_waitkey();
  2177.  
  2178.                       fg_setmode(old_mode);
  2179.                       fg_reset();
  2180.                    }
  2181.  
  2182.  
  2183.  
  2184. Byte Boundaries
  2185.  
  2186.      Video memory, like standard random-access memory, is divided into units
  2187. called bytes.  In text modes, each byte holds either a character or an
  2188. attribute.  In graphics modes, each byte of video memory holds one or more
  2189. horizontally contiguous pixels.  If two adjacent horizontal pixels are stored
  2190. in different bytes, then we say that a byte boundary exists between the two
  2191. pixels.
  2192.  
  2193.      The number of pixels per byte depends on the video mode being used, so
  2194. the byte boundaries also depend on the video mode.  That is, a byte boundary
  2195. in a CGA graphics mode is not necessarily a byte boundary in an EGA graphics
  2196. mode.  The following table summarizes the number of pixels per byte of video
  2197. memory and the byte boundary sequences for each supported graphics video
  2198. mode.  Note that any horizontal coordinate whose value is a multiple of 8 is
  2199. always a byte boundary, regardless of the video mode.
  2200.  
  2201.                   mode    pixels   horizontal coordinates
  2202.                  number  per byte  of byte boundaries
  2203.  
  2204.                    4         4     0, 4,  8, 12, ... , 316
  2205.                    5         4     0, 4,  8, 12, ... , 316
  2206.                    6         8     0, 8, 16, 24, ... , 632
  2207.                    9         2     0, 2,  4,  6, ... , 318
  2208.                    11        8     0, 8, 16, 24, ... , 712
  2209.                    12        4     0, 4,  8, 12, ... , 316
  2210.                    13        8     0, 8, 16, 24, ... , 312
  2211.                    14        8     0, 8, 16, 24, ... , 632
  2212.                    15        8     0, 8, 16, 24, ... , 632
  2213.                    16        8     0, 8, 16, 24, ... , 632
  2214.                    17        8     0, 8, 16, 24, ... , 632
  2215.                    18        8     0, 8, 16, 24, ... , 632
  2216.                    19        1     0, 1,  2,  3, ... , 319
  2217.                    20        1     0, 1,  2,  3, ... , 319
  2218.                    21        1     0, 1,  2,  3, ... , 319
  2219.                    22        1     0, 1,  2,  3, ... , 319
  2220.                    23        1     0, 1,  2,  3, ... , 319
  2221.  
  2222.                                   Chapter 9:  Images and Image Management  175
  2223.  
  2224.  
  2225. Image Transfer Routines
  2226.  
  2227.      The Fastgraph routines described in this section transfer images between
  2228. areas of video memory.  These routines are often used in animation sequences
  2229. requiring high-performance graphics, so they must be as efficient as
  2230. possible.  To this end, Fastgraph will force their horizontal pixel
  2231. coordinates to byte boundaries, which eliminates the need to process any
  2232. pixels individually.  Fastgraph accomplishes this by reducing minimum
  2233. horizontal coordinates to a byte boundary and extending maximum horizontal
  2234. coordinates to the last pixel in a video memory byte.  Note that since we are
  2235. talking about pixel coordinates and not character cells, the coordinate
  2236. modification only occurs in graphics video modes.
  2237.  
  2238.      An example might best help explain this important feature.  The CGA
  2239. four-color graphics modes (modes 4 and 5) store four pixels in each byte of
  2240. video memory.  This means the byte boundaries occur at multiples of four
  2241. pixels.  Thus, when you use the image transfer routines in modes 4 and 5,
  2242. Fastgraph reduces minimum x coordinates to the next lower multiple of four.
  2243. Similarly, it extends their maximum x coordinates to the next higher multiple
  2244. of four, less one pixel.  That is, if a minimum x coordinate is 7 and a
  2245. maximum x coordinate is 30, Fastgraph will modify these values to 4 and 31
  2246. respectively.  If the x coordinates were originally 4 and 31, Fastgraph would
  2247. leave them unchanged.  Note, too, that because each pixel in the MCGA and VGA
  2248. 256-color graphics modes (modes 19 through 23) occupies a separate byte of
  2249. video memory, Fastgraph does not need to modify horizontal coordinates in
  2250. these video modes.
  2251.  
  2252.      Fastgraph's simplest image transfer routine is fg_copypage, which we
  2253. introduced in Chapter 8.  The fg_copypage routine transfers the entire
  2254. contents of one video page to another.  The first argument is the number of
  2255. the source video page, and the second argument is the number of the
  2256. destination video page.  The pages may be physical, virtual, or logical video
  2257. pages.  If both the source and destination pages are logical pages, the pages
  2258. must exist in the same type of memory.  For example, you cannot copy a
  2259. logical page in extended memory to a logical page in conventional memory.
  2260.  
  2261.      Example 9-22 illustrates the use of the fg_copypage routine in a 320 x
  2262. 200 color graphics mode.  The program displays the word "test" in the middle
  2263. of the visual page (page 0) and then uses fg_allocate to create a virtual
  2264. video page (page 1).  The virtual page is needed in case the program is
  2265. running in a video mode with only one physical page.  Next, the program uses
  2266. 176  Fastgraph User's Guide
  2267.  
  2268. fg_copypage to transfer the visual page contents to page 1.  After waiting
  2269. for a keystroke, the program erases the visual page, waits for another
  2270. keystroke, and copies the contents of page 1 back to the visual page.  It
  2271. then releases the virtual page and exits.
  2272.  
  2273.                                 Example 9-22.
  2274.  
  2275.                 #include <fastgraf.h>
  2276.                 #include <stdio.h>
  2277.                 #include <stdlib.h>
  2278.                 void main(void);
  2279.  
  2280.                 void main()
  2281.                 {
  2282.                    int new_mode, old_mode;
  2283.  
  2284.                    new_mode = fg_bestmode(320,200,2);
  2285.                    if (new_mode < 0 || new_mode == 12) {
  2286.                       printf("This program requires a 320 ");
  2287.                       printf("x 200 color graphics mode.\n");
  2288.                       exit(1);
  2289.                       }
  2290.                    old_mode = fg_getmode();
  2291.                    fg_setmode(new_mode);
  2292.  
  2293.                    fg_setcolor(7);
  2294.                    fg_rect(0,319,0,199);
  2295.                    fg_setcolor(9);
  2296.                    fg_locate(12,18);
  2297.                    fg_text("test",4);
  2298.                    fg_waitkey();
  2299.  
  2300.                    fg_allocate(1);
  2301.                    fg_copypage(0,1);
  2302.                    fg_erase();
  2303.                    fg_waitkey();
  2304.  
  2305.                    fg_copypage(1,0);
  2306.                    fg_waitkey();
  2307.  
  2308.                    fg_freepage(1);
  2309.                    fg_setmode(old_mode);
  2310.                    fg_reset();
  2311.                 }
  2312.  
  2313.      Several of Fastgraph's image transfer routines reference a video page
  2314. called the hidden page.  The Fastgraph routine fg_sethpage defines which
  2315. video page will be used as the hidden page.  This routine takes as its only
  2316. argument an integer value specifying the hidden page number.  If you are
  2317. using a virtual video page for the hidden page, you must call the fg_sethpage
  2318. routine after allocating that page.  There is also a routine named
  2319. fg_gethpage that returns the hidden page number, as specified in the most
  2320. recent call to fg_sethpage, as its function value.  The fg_gethpage routine
  2321. takes no arguments.
  2322.  
  2323.      The next two image transfer routines we'll discuss are fg_save and
  2324. fg_restore.  The fg_save routine transfers a rectangular region from the
  2325.                                   Chapter 9:  Images and Image Management  177
  2326.  
  2327. active video page (as defined in the most recent call to fg_setpage) to the
  2328. same position on the hidden video page (as defined in the most recent call to
  2329. fg_sethpage).  The fg_restore routine performs the complementary task -- it
  2330. transfers a rectangular region from the hidden page to the active page.  Each
  2331. of these routines requires four arguments that define the coordinates of the
  2332. region to transfer, in the order minimum x, maximum x, minimum y, and maximum
  2333. y.  In text modes, the coordinates are expressed as character space
  2334. quantities (rows and columns).  In graphics modes, they are expressed as
  2335. screen space values (pixels); the x coordinates are extended to byte
  2336. boundaries if required.  There are also world space versions of these
  2337. routines named fg_savew and fg_restorew available in graphics modes.
  2338.  
  2339.      Example 9-23 demonstrates the use of Fastgraph's fg_save, fg_restore,
  2340. and fg_sethpage routines in an 80-column text video mode.  After establishing
  2341. the video mode (note the calls to fg_testmode specify that two video pages
  2342. are needed), the program fills the screen with text and then waits for a
  2343. keystroke.  Following this, the program displays a small pop-up window
  2344. prompting for another keystroke.  After waiting for the second keystroke, the
  2345. program erases the pop-up window by restoring the original screen contents,
  2346. and then waits for yet another keystroke before returning to DOS.  We'll
  2347. present the program now, and afterward analyze it in detail.
  2348.  
  2349.                                 Example 9-23.
  2350.  
  2351.                 #include <fastgraf.h>
  2352.                 #include <stdio.h>
  2353.                 #include <stdlib.h>
  2354.                 void main(void);
  2355.  
  2356.                 void main()
  2357.                 {
  2358.                    int row;
  2359.                    int old_mode;
  2360.                    char string[17];
  2361.  
  2362.                    old_mode = fg_getmode();
  2363.  
  2364.                    if (fg_testmode(3,2))
  2365.                       fg_setmode(3);
  2366.                    else if (fg_testmode(7,2))
  2367.                       fg_setmode(7);
  2368.                    else {
  2369.                       printf("This program requires\n");
  2370.                       printf("an 80-column display.\n");
  2371.                       exit(1);
  2372.                       }
  2373.                    fg_cursor(0);
  2374.                    fg_setattr(9,7,0);
  2375.  
  2376.                    for (row = 0; row < 25; row++) {
  2377.                       sprintf(string," This is row %2d ",row);
  2378.                       fg_locate(row,0);
  2379.                       fg_text(string,16);
  2380.                       fg_text(string,16);
  2381.                       fg_text(string,16);
  2382.                       fg_text(string,16);
  2383.  
  2384. 178  Fastgraph User's Guide
  2385.  
  2386.                       fg_text(string,16);
  2387.                       }
  2388.                    fg_waitkey();
  2389.  
  2390.                    fg_allocate(1);
  2391.                    fg_sethpage(1);
  2392.                    fg_save(32,47,11,13);
  2393.                    fg_setcolor(1);
  2394.                    fg_rect(32,47,11,13);
  2395.                    fg_setattr(15,1,0);
  2396.                    fg_locate(12,33);
  2397.                    fg_text("Press any key.",14);
  2398.                    fg_waitkey();
  2399.  
  2400.                    fg_restore(32,47,11,13);
  2401.                    fg_waitkey();
  2402.  
  2403.                    fg_freepage(1);
  2404.                    fg_setmode(old_mode);
  2405.                    fg_reset();
  2406.                 }
  2407.  
  2408.      Example 9-23 first establishes the video mode and uses the fg_cursor
  2409. routine to make the BIOS cursor invisible.  It then executes a for loop that
  2410. fills each row of the screen with the phrase "This is row n", where n is the
  2411. row number (between 0 and 24).  Next, the program uses the fg_allocate
  2412. routine to create video page 1 as a virtual video page.  This is needed in
  2413. case the program is running in mode 7, which has only one true page (if the
  2414. program is running in mode 3, the call to fg_allocate has no effect).  The
  2415. program then makes page 1 the hidden page by calling the fg_sethpage routine.
  2416.  
  2417.      After setting up the hidden video page, but before displaying the pop-up
  2418. window, example 9-23 uses the fg_save routine to save the current contents of
  2419. the area that the pop-up window will replace.  The fg_save routine copies
  2420. this region to the hidden page.  The program then displays the pop-up window
  2421. in the middle of the screen and leaves it there until a key is pressed.  After
  2422. this, the program uses the fg_restore routine to replace the pop-up window
  2423. with the original contents of that region.  This effectively erases the pop-up
  2424. window and restores the original screen.  The program then waits for another
  2425. keystroke, after which it releases the virtual page and returns to DOS.
  2426.  
  2427.      The next example, 9-24, is similar to example 9-23, but it runs in a 320
  2428. by 200 color graphics mode instead of a text mode.  The main differences
  2429. between this program and example 9-23 are the use of 40-column text and the
  2430. use of screen space coordinates instead of character space coordinates in the
  2431. calls to fg_save, fg_restore, and fg_rect.  Note that the call to fg_allocate
  2432. creates a virtual page if the program is running in modes 4, 9, or 19.  In
  2433. mode 13, which has 8 true pages, the fg_allocate routine does nothing.
  2434.  
  2435.                                 Example 9-24.
  2436.  
  2437.               #include <fastgraf.h>
  2438.               #include <stdio.h>
  2439.               #include <stdlib.h>
  2440.               void main(void);
  2441.  
  2442.                                   Chapter 9:  Images and Image Management  179
  2443.               void main()
  2444.               {
  2445.                  int row;
  2446.                  int new_mode, old_mode;
  2447.                  char string[21];
  2448.  
  2449.                  new_mode = fg_bestmode(320,200,2);
  2450.                  if (new_mode < 0 || new_mode == 12) {
  2451.                     printf("This program requires a 320 ");
  2452.                     printf("x 200 color graphics mode.\n");
  2453.                     exit(1);
  2454.                     }
  2455.                  old_mode = fg_getmode();
  2456.                  fg_setmode(new_mode);
  2457.  
  2458.                  fg_setcolor(7);
  2459.                  fg_rect(0,319,0,199);
  2460.                  fg_setcolor(9);
  2461.  
  2462.                  for (row = 0; row < 25; row++) {
  2463.                     sprintf(string,"   This is row %2d   ",row);
  2464.                     fg_locate(row,0);
  2465.                     fg_text(string,20);
  2466.                     fg_text(string,20);
  2467.                     }
  2468.                  fg_waitkey();
  2469.  
  2470.                  fg_allocate(1);
  2471.                  fg_sethpage(1);
  2472.                  fg_save(96,223,88,111);
  2473.                  fg_setcolor(1);
  2474.                  fg_rect(96,223,88,111);
  2475.                  fg_setcolor(15);
  2476.                  fg_locate(12,13);
  2477.                  fg_text("Press any key.",14);
  2478.                  fg_waitkey();
  2479.  
  2480.                  fg_restore(96,223,88,111);
  2481.                  fg_waitkey();
  2482.  
  2483.                  fg_freepage(1);
  2484.                  fg_setmode(old_mode);
  2485.                  fg_reset();
  2486.               }
  2487.  
  2488.      The fg_save and fg_restore routines each copy a rectangular region from
  2489. one video page to the same position on another video page.  What if you need
  2490. to copy the region to a different position on another video page, or copy it
  2491. elsewhere on the same video page?  Fastgraph provides a more general image
  2492. transfer routine named fg_transfer.  The fg_transfer routine copies a
  2493. rectangular region on any video page to any position on any video page.  Like
  2494. fg_save and fg_restore, the fg_transfer routine works in text and graphics
  2495. video modes.  In graphics modes, fg_transfer extends its x coordinates to
  2496. byte boundaries if necessary.
  2497.  
  2498.      The fg_transfer routine requires eight integer arguments.  The first
  2499. four arguments define the region to copy, in the same order as expected by
  2500. the fg_save and fg_restore routines.  The next two arguments define the lower
  2501. 180  Fastgraph User's Guide
  2502.  
  2503. left corner of the image destination, while the final two arguments
  2504. respectively specify the source and destination video page numbers.  In
  2505. short, fg_transfer copies the specified region from the source page to the
  2506. specified position on the destination page.
  2507.  
  2508.      Example 9-25 is the same as example 9-23, but it uses fg_transfer rather
  2509. than fg_save and fg_restore.  We have arbitrarily chosen to copy the region
  2510. overwritten by the pop-up window to the lower left corner of the hidden page
  2511. (page 1).  When we copy this region back to the visual page, we copy from the
  2512. lower left corner of the hidden page back to the original position on the
  2513. visual page (page 0).  This sequence is shown in the following diagram.
  2514.  
  2515.              (11,32)    (11,47)               (22,0)     (22,15)
  2516.                                 first call
  2517.                This is row 11   ------------>   This is row 11
  2518.                This is row 12                   This is row 12
  2519.                This is row 13   <------------   This is row 13
  2520.                                   second call
  2521.              (13,32)    (13,47)               (24,0)     (24,15)
  2522.  
  2523.                 visual page (0)                  hidden page (1)
  2524.  
  2525. To copy one region to a new position and then back to its original position,
  2526. note how we make the fifth and sixth arguments in the first call to
  2527. fg_transfer the same values as the first and fourth arguments in the second
  2528. call.  Similarly, the fifth and sixth arguments in the second call must be
  2529. the same as the first and fourth arguments in the first call.  Now, here is
  2530. example 9-25.
  2531.  
  2532.                                 Example 9-25.
  2533.  
  2534.                 #include <fastgraf.h>
  2535.                 #include <stdio.h>
  2536.                 #include <stdlib.h>
  2537.                 void main(void);
  2538.  
  2539.                 void main()
  2540.                 {
  2541.                    int row;
  2542.                    int old_mode;
  2543.                    char string[17];
  2544.  
  2545.                    old_mode = fg_getmode();
  2546.  
  2547.                    if (fg_testmode(3,2))
  2548.                       fg_setmode(3);
  2549.                    else if (fg_testmode(7,2))
  2550.                       fg_setmode(7);
  2551.                    else {
  2552.                       printf("This program requires\n");
  2553.                       printf("an 80-column display.\n");
  2554.                       exit(1);
  2555.                       }
  2556.  
  2557.                    fg_cursor(0);
  2558.                    fg_setattr(9,7,0);
  2559.  
  2560.                                   Chapter 9:  Images and Image Management  181
  2561.  
  2562.                    for (row = 0; row < 25; row++) {
  2563.                       sprintf(string," This is row %2d ",row);
  2564.                       fg_locate(row,0);
  2565.                       fg_text(string,16);
  2566.                       fg_text(string,16);
  2567.                       fg_text(string,16);
  2568.                       fg_text(string,16);
  2569.                       fg_text(string,16);
  2570.                       }
  2571.                    fg_waitkey();
  2572.  
  2573.                    fg_allocate(1);
  2574.                    fg_transfer(32,47,11,13,0,24,0,1);
  2575.                    fg_setcolor(1);
  2576.                    fg_rect(32,47,11,13);
  2577.                    fg_setattr(15,1,0);
  2578.                    fg_locate(12,33);
  2579.                    fg_text("Press any key.",14);
  2580.                    fg_waitkey();
  2581.  
  2582.                    fg_transfer(0,15,22,24,32,13,1,0);
  2583.                    fg_fg_waitkey();
  2584.  
  2585.                    fg_freepage(1);
  2586.                    fg_setmode(old_mode);
  2587.                    fg_reset();
  2588.                 }
  2589.  
  2590.      Example 9-26 illustrates another use of the fg_transfer routine.  This
  2591. example is functionally identical to example 9-18 (see page 170), but it uses
  2592. fg_transfer instead of fg_getmap and fg_drawmap.  With the fg_transfer
  2593. routine, we eliminate the calls to fg_getmap and fg_drawmap, the two calls to
  2594. fg_move, and the 32-byte array needed to retrieve the image.  As an added
  2595. bonus, using fg_transfer is much faster than the technique of example 9-18,
  2596. although we probably won't notice this gain with such a small image.
  2597.  
  2598.      The image copied in example 9-26 is one row of four characters, so its
  2599. width in screen space is 32 pixels and its height is 8 pixels.  Because the
  2600. image is in the upper left corner of the screen, the image boundaries are
  2601. xmin=0, xmax=31, ymin=0, and ymax=7.  We want to move the image one-half
  2602. character cell (4 pixels) to the right and one row (8 pixels) down, so our
  2603. destination coordinates are x=4 (xmin+4) and y=15 (ymax+8).  Also, we are
  2604. copying the image from one position to another on the visual page, so both
  2605. the source and destination pages are 0.
  2606.  
  2607.                                 Example 9-26.
  2608.  
  2609.                 #include <fastgraf.h>
  2610.                 #include <stdio.h>
  2611.                 #include <stdlib.h>
  2612.                 void main(void);
  2613.  
  2614.                 void main()
  2615.                 {
  2616.                    int old_mode, new_mode;
  2617.  
  2618. 182  Fastgraph User's Guide
  2619.  
  2620.                    new_mode = fg_bestmode(320,200,1);
  2621.                    if (new_mode < 0 || new_mode == 12) {
  2622.                       printf("This program requires a 320 ");
  2623.                       printf("x 200 color graphics mode.\n");
  2624.                       exit(1);
  2625.                       }
  2626.  
  2627.                    old_mode = fg_getmode();
  2628.                    fg_setmode(new_mode);
  2629.  
  2630.                    fg_setcolor(9);
  2631.                    fg_text("text",4);
  2632.                    fg_waitkey();
  2633.  
  2634.                    fg_transfer(0,31,0,7,4,15,0,0);
  2635.                    fg_waitkey();
  2636.  
  2637.                    fg_setmode(old_mode);
  2638.                    fg_reset();
  2639.                 }
  2640.  
  2641.      Example 9-27 shows yet another application of the fg_transfer routine in
  2642. a graphics video mode.  The program displays a rectangle in the upper left
  2643. quadrant of the screen and then centers the word "quadrant" inside the
  2644. rectangle.  After waiting for a keystroke, the program uses fg_transfer to
  2645. first copy the upper left quadrant to the upper right quadrant.  It then uses
  2646. fg_transfer again to copy the upper half of the screen to the lower half.
  2647. The result of this is the screen being filled with what was originally in the
  2648. upper left quadrant.
  2649.  
  2650.                                 Example 9-27.
  2651.  
  2652.                 #include <fastgraf.h>
  2653.                 #include <stdio.h>
  2654.                 #include <stdlib.h>
  2655.                 void main(void);
  2656.  
  2657.                 void main()
  2658.                 {
  2659.                    int new_mode, old_mode;
  2660.  
  2661.                    new_mode = fg_bestmode(320,200,1);
  2662.                    if (new_mode < 0 || new_mode == 12) {
  2663.                       printf("This program requires a 320 ");
  2664.                       printf("x 200 color graphics mode.\n");
  2665.                       exit(1);
  2666.                       }
  2667.                    old_mode = fg_getmode();
  2668.                    fg_setmode(new_mode);
  2669.  
  2670.                    fg_setcolor(7);
  2671.                    fg_rect(0,159,0,99);
  2672.                    fg_setcolor(9);
  2673.                    fg_locate(6,6);
  2674.                    fg_text("quadrant",8);
  2675.                    fg_waitkey();
  2676.  
  2677.                                   Chapter 9:  Images and Image Management  183
  2678.  
  2679.                    fg_transfer(0,159,0,99,160, 99,0,0);
  2680.                    fg_transfer(0,319,0,99,  0,199,0,0);
  2681.                    fg_waitkey();
  2682.  
  2683.                    fg_setmode(old_mode);
  2684.                    fg_reset();
  2685.                 }
  2686.  
  2687.      The final routines pertaining to image transfer are fg_tcxfer and
  2688. fg_tcmask.  The fg_tcxfer routine is similar to fg_transfer in that it copies
  2689. a rectangular region from one position to another, but fg_tcxfer allows you
  2690. to treat one or more colors as transparent (the name fg_tcxfer stands for
  2691. "transparent color transfer").  In other words, any pixel whose color value
  2692. is defined to be transparent is not copied to the destination area.  The
  2693. fg_tcxfer routine's arguments are the same as for the fg_transfer routine, but
  2694. fg_tcxfer has no effect in text video modes.  Because fg_tcxfer must examine
  2695. the color of individual pixels, it is not as fast as the fg_transfer routine.
  2696.  
  2697.      The fg_tcmask routine defines which colors are considered transparent in
  2698. subsequent calls to fg_tcxfer.  Its argument is an integer bit mask
  2699. (specifically, a 16-bit mask) where each bit indicates whether or not the
  2700. color is transparent.  For example, if bit 0 (the rightmost bit) is set in
  2701. the mask, then color 0 will be transparent; if bit 0 is reset, color 0 will
  2702. not be transparent.  Because the bit mask size is 16 bits, only the first 16
  2703. color values may be defined as transparent.
  2704.  
  2705.      Example 9-28 illustrates the use of the fg_tcxfer and fg_tcmask routines.
  2706. This program is the same as example 9-27, except the color of the word
  2707. "quadrant" (color 9) is defined to be transparent, and fg_tcxfer is used in
  2708. place of fg_transfer.  Because color 9 maps to color 1 in the CGA four-color
  2709. graphics mode (mode 4), we must define both colors 1 and 9 to be transparent
  2710. (remember, fg_tcmask considers actual color values transparent, not color
  2711. indices).  The bit mask passed to fg_tcmask thus will be 0000 0010 0000 0010
  2712. binary, or 0202 hex.  The result of this program is the same as example 9-27,
  2713. but the word "quadrant" appears in the background color (color 0) instead of
  2714. color 9 in the upper right, lower left, and lower right quadrants.
  2715.  
  2716.                                 Example 9-28.
  2717.  
  2718.                 #include <fastgraf.h>
  2719.                 #include <stdio.h>
  2720.                 #include <stdlib.h>
  2721.                 void main(void);
  2722.  
  2723.                 void main()
  2724.                 {
  2725.                    int new_mode, old_mode;
  2726.  
  2727.                    new_mode = fg_bestmode(320,200,1);
  2728.                    if (new_mode < 0 || new_mode == 12) {
  2729.                       printf("This program requires a 320 ");
  2730.                       printf("x 200 color graphics mode.\n");
  2731.                       exit(1);
  2732.                       }
  2733.                    old_mode = fg_getmode();
  2734.                    fg_setmode(new_mode);
  2735.  
  2736. 184  Fastgraph User's Guide
  2737.  
  2738.                    fg_setcolor(7);
  2739.                    fg_rect(0,159,0,99);
  2740.                    fg_setcolor(9);
  2741.                    fg_locate(6,6);
  2742.                    fg_text("quadrant",8);
  2743.                    fg_waitkey();
  2744.  
  2745.                    fg_tcmask(0x0202);
  2746.                    fg_tcxfer(0,159,0,99,160, 99,0,0);
  2747.                    fg_tcxfer(0,319,0,99,  0,199,0,0);
  2748.                    fg_waitkey();
  2749.  
  2750.                    fg_setmode(old_mode);
  2751.                    fg_reset();
  2752.                 }
  2753.  
  2754.  
  2755.  
  2756. Summary of Image Display Routines
  2757.  
  2758.      This section summarizes the functional descriptions of the Fastgraph
  2759. routines presented in this chapter.  More detailed information about these
  2760. routines, including their arguments and return values, may be found in the
  2761. Fastgraph Reference Manual.
  2762.  
  2763.      For all image display routines, images are positioned so their lower
  2764. left corner is at the graphics cursor position (or text cursor position for
  2765. those routines that also work in text video modes).  For all image transfer
  2766. routines, Fastgraph extends the horizontal pixel coordinates to a byte
  2767. boundary when the routines are used in a graphics video mode.
  2768.  
  2769.      FG_CLIPMASK displays a clipped image stored as a masking map.  This
  2770. routine has no effect when used in a text video mode.
  2771.  
  2772.      FG_CLPIMAGE displays a clipped image stored as a mode-specific bit map.
  2773. This routine has no effect when used in a text video mode.
  2774.  
  2775.      FG_COPYPAGE transfers the contents of one video page to another.  The
  2776. pages may be physical, virtual, or logical video pages.  If both pages are
  2777. logical pages, they must exist in the same type of memory.
  2778.  
  2779.      FG_DISPFILE displays an image stored in Fastgraph's standard or packed
  2780. pixel run format, where the image resides in an external file.  This routine
  2781. has no effect when used in a text video mode.
  2782.  
  2783.      FG_DISPLAY displays an image stored in Fastgraph's standard pixel run
  2784. format, where the image resides in an array.  This routine has no effect when
  2785. used in a text video mode.
  2786.  
  2787.      FG_DISPLAYP displays an image stored in Fastgraph's packed pixel run
  2788. format, where the image resides in an array.  This routine has no effect when
  2789. used in a text video mode.
  2790.  
  2791.      FG_DISPPCX displays an image stored in a PCX file.  The image will be
  2792. positioned so its upper left corner is at the graphics cursor position of the
  2793. active video page.
  2794.                                   Chapter 9:  Images and Image Management  185
  2795.  
  2796.      FG_DRAWMAP displays an image stored as a mode-independent bit map.  This
  2797. routine has no effect when used in a text video mode.
  2798.  
  2799.      FG_DRAWMASK displays an image stored as a masking map.  This routine has
  2800. no effect when used in a text video mode.
  2801.  
  2802.      FG_DRWIMAGE displays an image stored as a mode-specific bit map.
  2803.  
  2804.      FG_FLIPMASK displays a reversed clipped image stored as a masking map.
  2805. This routine has no effect when used in a text video mode.
  2806.  
  2807.      FG_FLPIMAGE displays a reversed clipped image stored as a mode-specific
  2808. bit map.  This routine has no effect when used in a text video mode.
  2809.  
  2810.      FG_GETHPAGE returns the hidden page number, as defined in the most
  2811. recent call to fg_sethpage.
  2812.  
  2813.      FG_GETIMAGE retrieves an image as a mode-specific bit map.
  2814.  
  2815.      FG_GETMAP retrieves an image as a mode-independent bit map.  This
  2816. routine has no effect when used in a text video mode.
  2817.  
  2818.      FG_IMAGESIZ determines the number of bytes required to store a mode-
  2819. specific bit-mapped image of specified dimensions.
  2820.  
  2821.      FG_MAKEPCX creates a PCX file from the specified rectangular region of
  2822. the active video page.  The region's extremes are expressed in screen space
  2823. units.
  2824.  
  2825.      FG_PATTERN defines a display pattern for use with the fg_dispfile,
  2826. fg_display, or fg_displayp routines.  This routine has no effect when used in
  2827. a text video mode.
  2828.  
  2829.      FG_RESTORE copies an image from the hidden video page to the same
  2830. position on the active video page.
  2831.  
  2832.      FG_RESTOREW is the same as fg_restore, but the image extremes are
  2833. specified as world space coordinates.
  2834.  
  2835.      FG_REVIMAGE displays a reversed image stored as a mode-specific bit map.
  2836. This routine has no effect when used in a text video mode.
  2837.  
  2838.      FG_REVMASK displays a reversed image stored as a masking map.  This
  2839. routine has no effect when used in a text video mode.
  2840.  
  2841.      FG_SAVE copies an image from the active video page to the same position
  2842. on the hidden video page.
  2843.  
  2844.      FG_SAVEW is the same as fg_save, but the image extremes are specified as
  2845. world space coordinates.
  2846.  
  2847.      FG_SETHPAGE defines the hidden video page (used by fg_restore,
  2848. fg_restorew, fg_save, and fg_savew).
  2849.  
  2850.      FG_TCMASK defines which colors the fg_tcxfer routine will consider
  2851. transparent.  This routine has no effect when used in a text video mode.
  2852. 186  Fastgraph User's Guide
  2853.  
  2854.      FG_TCXFER copies an image from any position on any video page to any
  2855. position on any video page, excluding any pixels whose color value is
  2856. transparent.  This routine has no effect when used in a text video mode.
  2857.  
  2858.      FG_TRANSFER copies an image from any position on any video page to any
  2859. position on any video page.  It is Fastgraph's most general image transfer
  2860. routine.
  2861.  
  2862.  
  2863. Chapter 10
  2864.  
  2865. Animation Techniques
  2866. 188  Fastgraph User's Guide
  2867.  
  2868. Overview
  2869.  
  2870.      Unlike other microcomputers, the IBM PC and PS/2 family of systems do
  2871. not have any special graphics hardware or firmware to help in performing
  2872. animation.  This means that any animation done on these systems must be
  2873. implemented entirely through software.  This chapter will describe how to do
  2874. this using Fastgraph's video page management and image management routines.
  2875. The methods described in this chapter are not intended to be all inclusive,
  2876. for that would itself fill a separate volume at least as large as this
  2877. manual.  However, the animation techniques presented here should provide a
  2878. basis that you can readily extend to develop more sophisticated uses of
  2879. animation.  The examples in this chapter are restricted to graphics video
  2880. modes.
  2881.  
  2882.  
  2883. Simple Animation
  2884.  
  2885.      The first type of animation we'll examine is called simple animation.
  2886. In simple animation, we display an object, erase it, and then display it in a
  2887. new position.  When we perform this "erase and redisplay" sequence
  2888. repetitively, the object moves.  This method, however, has two drawbacks.
  2889. First, unless the object is rather small, it will flicker because the erasing
  2890. and display of the object does not coincide with the refresh rate of the
  2891. video display.  Second, and perhaps more importantly, anything underneath the
  2892. object is not saved as the object moves across it.  Despite these
  2893. limitations, simple animation is sometimes useful, and it is a good place to
  2894. begin our discussion of animation techniques.
  2895.  
  2896.      Example 10-1 moves a small bright green rectangle (magenta in CGA) from
  2897. left to right across the screen in any 320 by 200 color graphics mode.  The
  2898. program moves the rectangle, 20 pixels wide and 10 pixels high, using a for
  2899. loop.  This loop first uses the fg_clprect routine to display the rectangle,
  2900. then uses the fg_waitfor routine to leave the object on the screen
  2901. momentarily, and finally uses fg_clprect again to erase the rectangle by
  2902. redisplaying it in the original background color (the fg_waitfor routine is
  2903. described in Chapter 14).  We use fg_clprect rather than fg_rect because the
  2904. first few and last few loop iterations result in at least part of the
  2905. rectangle being off the screen.  Each successive loop iteration displays the
  2906. rectangle five pixels to the right of its previous position.
  2907.  
  2908.                                 Example 10-1.
  2909.  
  2910.           #include <fastgraf.h>
  2911.           #include <stdio.h>
  2912.           #include <stdlib.h>
  2913.           void main(void);
  2914.  
  2915.           void main()
  2916.           {
  2917.              int new_mode, old_mode;
  2918.              int x;
  2919.  
  2920.              /* initialize the video environment */
  2921.  
  2922.              new_mode = fg_bestmode(320,200,1);
  2923.              if (new_mode < 0 || new_mode == 12) {
  2924.  
  2925.                                         Chapter 10:  Animation Techniques  189
  2926.  
  2927.                 printf("This program requires a 320 ");
  2928.                 printf("x 200 color graphics mode.\n");
  2929.                 exit(1);
  2930.                 }
  2931.              old_mode = fg_getmode();
  2932.              fg_setmode(new_mode);
  2933.  
  2934.              /* move the object across the screen */
  2935.  
  2936.              for (x = -20; x < 320; x+=5) {
  2937.                 fg_setcolor(10);
  2938.                 fg_clprect(x,x+19,95,104);
  2939.                 fg_waitfor(1);
  2940.                 fg_setcolor(0);
  2941.                 fg_clprect(x,x+19,95,104);
  2942.                 }
  2943.  
  2944.              /* restore the original video mode and return to DOS */
  2945.  
  2946.              fg_setmode(old_mode);
  2947.              fg_reset();
  2948.           }
  2949.  
  2950.      Example 10-2 is the same as example 10-1, but it shows what happens when
  2951. we move the rectangle across an existing background (in this case, the
  2952. background is solid white).  If you run this program, you'll see that the
  2953. rectangle leaves a trail of color 0 behind it.  While this might be
  2954. occasionally useful, it demonstrates that simple animation is destructive
  2955. because it does not preserve the background.  In this example, if we changed
  2956. the second call to fg_setcolor within the for loop so revert to color 15
  2957. instead of color 0, the background would be restored.  In general, though, it
  2958. may not be this easy to replace the background, so we must rely on some other
  2959. method for preserving it.
  2960.  
  2961.                                 Example 10-2.
  2962.  
  2963.           #include <fastgraf.h>
  2964.           #include <stdio.h>
  2965.           #include <stdlib.h>
  2966.           void main(void);
  2967.  
  2968.           void main()
  2969.           {
  2970.              int new_mode, old_mode;
  2971.              int x;
  2972.  
  2973.              /* initialize the video environment */
  2974.  
  2975.              new_mode = fg_bestmode(320,200,1);
  2976.              if (new_mode < 0 || new_mode == 12) {
  2977.                 printf("This program requires a 320 ");
  2978.                 printf("x 200 color graphics mode.\n");
  2979.                 exit(1);
  2980.                 }
  2981.              old_mode = fg_getmode();
  2982.              fg_setmode(new_mode);
  2983.  
  2984. 190  Fastgraph User's Guide
  2985.  
  2986.              /* draw some type of background */
  2987.  
  2988.              fg_setcolor(15);
  2989.              fg_rect(0,319,0,199);
  2990.  
  2991.              /* move the object across the screen */
  2992.  
  2993.              for (x = -20; x < 320; x+=5) {
  2994.                 fg_setcolor(10);
  2995.                 fg_clprect(x,x+19,95,104);
  2996.                 fg_waitfor(1);
  2997.                 fg_setcolor(0);
  2998.                 fg_clprect(x,x+19,95,104);
  2999.                 }
  3000.  
  3001.              /* restore the original video mode and return to DOS */
  3002.  
  3003.              fg_setmode(old_mode);
  3004.              fg_reset();
  3005.           }
  3006.  
  3007.      To summarize, we see that simple animation is easy to implement, but it
  3008. is destructive and typically causes the animated object to flicker.  For
  3009. these reasons, it is not used too frequently.
  3010.  
  3011.  
  3012. XOR Animation
  3013.  
  3014.      "Exclusive or" animation, or XOR animation for short, is an interesting
  3015. extension of simple animation and is most useful when animating a single-
  3016. color object against a single-color background.  Like simple animation, it
  3017. uses the "erase and redisplay" technique to move an object, but it does this
  3018. differently.  Instead of erasing the object by displaying it in the
  3019. background color, XOR animation does so by displaying it in the same color
  3020. using an exclusive or, or XOR, operation.  This method relies on a specific
  3021. property of the exclusive or operator:
  3022.  
  3023.                (object XOR background) XOR object = background
  3024.  
  3025. In other words, if you XOR something twice in the same position, the result
  3026. is the same as the original image in that position.
  3027.  
  3028.      Example 10-3 demonstrates XOR animation.  This program is similar to
  3029. example 10-2, but it only runs in the 320 by 200 EGA graphics mode (mode 13).
  3030. After establishing the video mode, it uses the Fastgraph routine fg_setfunc
  3031. to select XOR mode.  This causes any subsequent graphics output to be XORed
  3032. with the contents of video memory instead of just replacing it.  The
  3033. fg_setfunc routine is described further in Chapter 15.
  3034.  
  3035.      The other differences between examples 10-3 and 10-2 are that the call
  3036. to fg_setcolor has been moved outside the for loop, and that fg_setcolor
  3037. takes a different value.  Since the existing background is bright white
  3038. (color 15), we can't just use color 10 if we want to display a bright green
  3039. object.  The desired value is that which when XORed with color 15 produces
  3040. color 10; the easiest way to obtain this value is to XOR these two numbers.
  3041. The call to fg_setcolor can be moved outside the loop because we display the
  3042. object using the same color index throughout.
  3043.                                         Chapter 10:  Animation Techniques  191
  3044.  
  3045.                                 Example 10-3.
  3046.  
  3047.           #include <fastgraf.h>
  3048.           #include <stdio.h>
  3049.           #include <stdlib.h>
  3050.           void main(void);
  3051.  
  3052.           void main()
  3053.           {
  3054.              int old_mode;
  3055.              int x;
  3056.  
  3057.              /* initialize the video environment */
  3058.  
  3059.              if (fg_testmode(13,1) == 0) {
  3060.                 printf("This program requires EGA.\n");
  3061.                 exit(1);
  3062.                 }
  3063.              old_mode = fg_getmode();
  3064.              fg_setmode(13);
  3065.              fg_setfunc(3);
  3066.  
  3067.              /* draw some type of background */
  3068.  
  3069.              fg_setcolor(15);
  3070.              fg_rect(0,319,0,199);
  3071.  
  3072.              /* move the object across the screen */
  3073.  
  3074.              fg_setcolor(10^15);
  3075.              for (x = -20; x < 320; x+=5) {
  3076.                 fg_clprect(x,x+19,95,104);
  3077.                 fg_waitfor(1);
  3078.                 fg_clprect(x,x+19,95,104);
  3079.                 }
  3080.  
  3081.              /* restore the original video mode and return to DOS */
  3082.  
  3083.              fg_setmode(old_mode);
  3084.              fg_reset();
  3085.           }
  3086.  
  3087.  
  3088.      Fastgraph only supports the XOR pixel operation in the native EGA and
  3089. VGA graphics video modes (modes 13 through 18).  Thus, you cannot use XOR
  3090. animation in CGA, Tandy/PCjr, Hercules, or MCGA graphics modes.
  3091.  
  3092.      While XOR animation is non-destructive (that is, it restores the
  3093. original background), it still suffers from the flickering encountered in
  3094. simple animation.  In spite of this, it may be useful when animating a
  3095. single-color object against a single-color background.
  3096. 192  Fastgraph User's Guide
  3097.  
  3098.  
  3099. Static Frame Animation
  3100.  
  3101.      Static frame animation uses a different strategy than simple animation
  3102. or XOR animation.  The general scheme of this method is to create the entire
  3103. animation sequence off-screen and then successively display each item, or
  3104. frame, in this sequence on one position of the visual video page.  This
  3105. results in a visually appealing animation that is non-destructive and does
  3106. not include the flickering associated with simple animation and XOR
  3107. animation.  Static frame animation requires the visual video page and one or
  3108. more additional pages to implement.  The number of pages needed depends on
  3109. the number of frames and the size of each frame.
  3110.  
  3111.      Example 10-4 runs in any 320 by 200 color graphics video mode and
  3112. illustrates a simple use of static frame animation.  The program displays an
  3113. animation sequence containing 12 frames; it displays this sequence three
  3114. times.  The animation sequence consists of a bright green rectangle (magenta
  3115. in CGA) moving from left to right across the center of the frame.  Each frame
  3116. is 96 pixels wide and 50 pixels high.  The 12 frames are set up on an off-
  3117. screen video page as shown below.
  3118.  
  3119.                          0       95 96     191 192    287
  3120.  
  3121.                       0
  3122.                           frame 1    frame 2    frame 3
  3123.                      49
  3124.  
  3125.                      50
  3126.                           frame 4    frame 5    frame 6
  3127.                      99
  3128.  
  3129.                     100
  3130.                           frame 7    frame 8    frame 9
  3131.                     149
  3132.  
  3133.                     150
  3134.                           frame 10   frame 11   frame 12
  3135.                     199
  3136.  
  3137.      Example 10-4 first establishes the video mode and allocates the
  3138. additional video page (needed if using a video mode in which page 1 is a
  3139. virtual video page).  The program then generates the background for frame 1;
  3140. the background is a blue rectangle (cyan in CGA) with a white ellipse
  3141. centered on it.  After the call to fg_ellipse, the first frame is ready.
  3142.  
  3143.      The next step is to create the remaining 11 frames.  In frame 2, the
  3144. right half of the 20-pixel wide rectangle will enter the left edge of the
  3145. frame.  In frame 3, the rectangle will be ten pixels farther right, or
  3146. aligned against the left edge of the frame.  In frames 4 through 12, the
  3147. rectangle will be ten pixels farther right in each frame, so by frame 12 only
  3148. the left half of the rectangle appears on the right edge of the frame.  The
  3149. first for loop in the program builds frames 2 through 12 by copying the
  3150. background from frame 1 and then displaying the rectangle (that is, the
  3151. animated object) in the proper position for that frame.
  3152.  
  3153.      The second for loop performs the animation sequence.  To display the 12-
  3154. frame sequence three times, it must perform 36 iterations.  The loop simply
  3155.                                         Chapter 10:  Animation Techniques  193
  3156.  
  3157. copies each frame from the proper position on video page 1 to the middle of
  3158. the visual video page.  Note how the fg_waitfor routine is used to pause
  3159. momentarily between each frame.
  3160.  
  3161.                                 Example 10-4.
  3162.  
  3163.        #include <fastgraf.h>
  3164.        #include <stdio.h>
  3165.        #include <stdlib.h>
  3166.        void main(void);
  3167.  
  3168.        #define VISUAL 0
  3169.        #define HIDDEN 1
  3170.  
  3171.        int xmin[] = {  0, 96,192,  0, 96,192,  0, 96,192,  0, 96,192};
  3172.        int ymax[] = { 49, 49, 49, 99, 99, 99,149,149,149,199,199,199};
  3173.  
  3174.        void main()
  3175.        {
  3176.           int new_mode, old_mode;
  3177.           int frame, offset;
  3178.           int i, x, y;
  3179.  
  3180.           /* initialize the video environment */
  3181.  
  3182.           new_mode = fg_bestmode(320,200,2);
  3183.           if (new_mode < 0 || new_mode == 12) {
  3184.              printf("This program requires a 320 ");
  3185.              printf("x 200 color graphics mode.\n");
  3186.              exit(1);
  3187.              }
  3188.           old_mode = fg_getmode();
  3189.           fg_setmode(new_mode);
  3190.           fg_allocate(HIDDEN);
  3191.  
  3192.           /* draw the background in the upper left corner */
  3193.  
  3194.           fg_setpage(HIDDEN);
  3195.           fg_setcolor(1);
  3196.           fg_rect(0,95,0,49);
  3197.           fg_setcolor(15);
  3198.           fg_move(48,25);
  3199.           fg_ellipse(20,20);
  3200.  
  3201.           /* display the animated object against each background */
  3202.  
  3203.           fg_setcolor(10);
  3204.           offset = -10;
  3205.           for (i = 1; i < 12; i++) {
  3206.              x = xmin[i];
  3207.              y = ymax[i];
  3208.              fg_transfer(0,95,0,49,x,y,HIDDEN,HIDDEN);
  3209.              fg_setclip(x,x+95,0,199);
  3210.              fg_clprect(x+offset,x+offset+19,y-29,y-20);
  3211.              offset += 10;
  3212.              }
  3213.  
  3214. 194  Fastgraph User's Guide
  3215.  
  3216.           /* slide the object across the background three times */
  3217.  
  3218.           for (i = 0; i < 36; i++) {
  3219.              frame = i % 12;
  3220.              x = xmin[frame];
  3221.              y = ymax[frame];
  3222.              fg_transfer(x,x+95,y-49,y,112,124,HIDDEN,VISUAL);
  3223.              fg_waitfor(2);
  3224.              }
  3225.  
  3226.           /* restore the original video mode and return to DOS */
  3227.  
  3228.           fg_freepage(HIDDEN);
  3229.           fg_setmode(old_mode);
  3230.           fg_reset();
  3231.        }
  3232.  
  3233. Dynamic Frame Animation
  3234.  
  3235.      Dynamic frame animation is similar to static frame animation, but all
  3236. the animation frames are built as needed during the animation sequence
  3237. instead of in advance.  When using this method, you must first store a copy
  3238. of the background on an off-screen video page.  Then, to build a frame,
  3239. create another copy (called the workspace) of the background elsewhere on the
  3240. off-screen page (or even to a different off-screen page) and display the
  3241. object on that copy.  Finally, transfer the workspace to the visual page.
  3242. Like static frame animation, this method produces a non-destructive, flicker-
  3243. free animation sequence.
  3244.  
  3245.      Example 10-5 is functionally identical to example 10-4, but it uses
  3246. dynamic rather than static frame animation.  As before, the program builds
  3247. the background in the upper left corner of video page 1, but it then uses
  3248. fg_transfer to copy it to the center of the visual video page.  The for loop
  3249. builds each frame as it is needed and also copies it to the center of the
  3250. visual page.  Again, fg_waitfor creates the necessary pause between frames.
  3251.  
  3252.                                 Example 10-5.
  3253.  
  3254.          #include <fastgraf.h>
  3255.          #include <stdio.h>
  3256.          #include <stdlib.h>
  3257.          void main(void);
  3258.  
  3259.          #define VISUAL 0
  3260.          #define HIDDEN 1
  3261.  
  3262.          void main()
  3263.          {
  3264.             int new_mode, old_mode;
  3265.             int frame, offset;
  3266.             int i;
  3267.  
  3268.             /* initialize the video environment */
  3269.  
  3270.             new_mode = fg_bestmode(320,200,2);
  3271.             if (new_mode < 0 || new_mode == 12) {
  3272.  
  3273.                                         Chapter 10:  Animation Techniques  195
  3274.  
  3275.                printf("This program requires a 320 ");
  3276.                printf("x 200 color graphics mode.\n");
  3277.                exit(1);
  3278.                }
  3279.             old_mode = fg_getmode();
  3280.             fg_setmode(new_mode);
  3281.             fg_allocate(HIDDEN);
  3282.  
  3283.             /* draw the background in the upper left corner */
  3284.  
  3285.             fg_setpage(HIDDEN);
  3286.             fg_setcolor(1);
  3287.             fg_rect(0,95,0,49);
  3288.             fg_setcolor(15);
  3289.             fg_move(48,25);
  3290.             fg_ellipse(20,20);
  3291.  
  3292.             /* copy it to the center of the visual page */
  3293.  
  3294.             fg_transfer(0,95,0,49,112,124,HIDDEN,VISUAL);
  3295.  
  3296.             /* slide the object across the background three times */
  3297.  
  3298.             fg_setcolor(10);
  3299.             for (i = 0; i < 36; i++) {
  3300.                frame  = i % 12;
  3301.                offset = 10 * frame - 10;
  3302.                fg_transfer(0,95,20,29,112,105,HIDDEN,HIDDEN);
  3303.                fg_rect(112+offset,131+offset,96,105);
  3304.                fg_transfer(112,207,96,105,112,105,HIDDEN,VISUAL);
  3305.                fg_waitfor(2);
  3306.                }
  3307.  
  3308.             /* restore the original video mode and return to DOS */
  3309.  
  3310.             fg_freepage(HIDDEN);
  3311.             fg_setmode(old_mode);
  3312.             fg_reset();
  3313.          }
  3314.  
  3315.  
  3316.      Two items in example 10-5 merit further discussion.  First, we have
  3317. chosen our workspace on page 1 so it uses the same screen space coordinates
  3318. as the image area on the visual page.  This is not necessary unless you are
  3319. using the fg_restore routine instead of fg_transfer.  Second, the program can
  3320. use the faster fg_rect routine in place of fg_clprect.  It can do this
  3321. because even though the object will extend beyond the workspace limits, we
  3322. only transfer the workspace itself.  However, for this to function properly,
  3323. the workspace's horizontal limits must fall on byte boundaries.
  3324.  
  3325.      Note too that we do not need to transfer the entire frame during the
  3326. animation sequence.  In example 10-5, we know the vertical extremes of the
  3327. moving image are y=96 and y=105, so we only transfer 10 rows instead of the
  3328. entire frame.  We could similarly compute the x extremes for each frame and
  3329. only transfer the necessary portion.  Recall, however, that fg_transfer
  3330. extends the horizontal coordinates to byte boundaries, so we may copy a few
  3331. extra pixels as well.  This may or may not affect the animation sequence.
  3332. 196  Fastgraph User's Guide
  3333.  
  3334. Again, the problem is eliminated if you align your workspace on byte
  3335. boundaries.
  3336.  
  3337.      When we use dynamic frame animation, it is easy to change the number of
  3338. frames in the animation sequence.  Suppose we wish to produce a smoother
  3339. animation by increasing the number of frames from 12 to 24.  This means the
  3340. object will move in increments of five pixels instead of ten.  The only
  3341. changes needed are to double the number of loop iterations, modify the
  3342. calculations for the frame number and offset values as shown below, and
  3343. reduce the fg_waitfor pause from 2 to 1.
  3344.  
  3345.                            frame  = i % 24;
  3346.                            offset = 5 * frame - 10;
  3347.  
  3348. Compare this to all the changes that would be necessary if we were using
  3349. static frame animation.
  3350.  
  3351.  
  3352. Page Flipping
  3353.  
  3354.      Page flipping is a variation of frame animation in which you construct
  3355. images on off-screen video pages and then repetitively make those pages the
  3356. visual page.  We can further divide the page flipping technique into static
  3357. and dynamic variants, as we did with frame animation.
  3358.  
  3359.      In static page flipping, we construct the entire animation sequence in
  3360. advance, with one frame per video page.  Once this is done, we can display
  3361. each frame by using the fg_setvpage routine to switch instantly from one
  3362. video page to another.  Although this produces a smooth, flicker-free
  3363. animation, we cannot carry the sequence very far before running out of video
  3364. pages (and hence animation frames).
  3365.  
  3366.      In dynamic page flipping, we construct each animation frame when it is
  3367. needed.  As in static page flipping, we construct each frame on a separate
  3368. video page.  However, as example 10-6 demonstrates, we only need three video
  3369. pages to produce the animation sequence, regardless of the number of frames
  3370. in the sequence.  Two of the three video pages will alternate as the visual
  3371. page, while the remaining video page keeps a copy of the background.
  3372.  
  3373.      Example 10-6, which performs an animation sequence similar to examples
  3374. 10-4 and 10-5, illustrates dynamic frame animation in the 320 by 200 EGA
  3375. graphics video mode (mode 13).  The program begins by displaying the
  3376. background on video page 2.  Video pages 0 and 1 will alternate as the visual
  3377. page; the page that is not the visual page is called the hidden page.  We
  3378. start with page 0 as the visual page, and hence page 1 as the hidden page.
  3379. To build each frame, the program uses fg_transfer to copy the background from
  3380. page 2 to the hidden page and then uses fg_clprect to display the animated
  3381. object at the correct position on the hidden page.  After this, it displays
  3382. the next frame by using fg_setvpage to make the hidden page the visual page.
  3383. Before beginning the next iteration, the program toggles the hidden page
  3384. number in preparation for the next frame.
  3385.  
  3386.                                 Example 10-6.
  3387.  
  3388.           #include <fastgraf.h>
  3389.           #include <stdio.h>
  3390.  
  3391.                                         Chapter 10:  Animation Techniques  197
  3392.  
  3393.           #include <stdlib.h>
  3394.           void main(void);
  3395.  
  3396.           void main()
  3397.           {
  3398.              int old_mode;
  3399.              int hidden;
  3400.              int x;
  3401.  
  3402.              /* initialize the video environment */
  3403.  
  3404.              if (testmode(fg_13,3) == 0) {
  3405.                 printf("This program requires EGA.\n");
  3406.                 exit(1);
  3407.                 }
  3408.              old_mode = fg_getmode();
  3409.              fg_setmode(13);
  3410.  
  3411.              /* draw the background on page two */
  3412.  
  3413.              fg_setpage(2);
  3414.              fg_setcolor(1);
  3415.              fg_rect(0,319,0,199);
  3416.              fg_setcolor(15);
  3417.              fg_move(160,100);
  3418.              fg_ellipse(20,20);
  3419.  
  3420.              /* slide the object across the screen */
  3421.  
  3422.              hidden = 1;
  3423.              setcolor(10);
  3424.              for (x = -10; x < 320; x+=4) {
  3425.                 fg_setpage(hidden);
  3426.                 fg_transfer(0,319,0,199,0,199,2,hidden);
  3427.                 fg_clprect(x,x+19,96,105);
  3428.                 fg_setvpage(hidden);
  3429.                 hidden = 1 - hidden;
  3430.                 fg_waitfor(1);
  3431.                 }
  3432.  
  3433.              /* restore the original video mode and return to DOS */
  3434.  
  3435.              fg_setmode(old_mode);
  3436.              fg_reset();
  3437.           }
  3438.  
  3439.  
  3440.      A problem with either page flipping technique arises if we use virtual
  3441. video pages.  Page flipping relies on the fact that changing the visual page
  3442. number occurs instantly, which is exactly what happens when we use physical
  3443. video pages.  However, such is not the case with virtual or logical pages
  3444. because Fastgraph must copy the entire page contents into video memory.
  3445. While this occurs quite rapidly, it is not instantaneous, and its effects are
  3446. immediately apparent on the animation.
  3447. 198  Fastgraph User's Guide
  3448.  
  3449.  
  3450. Summary of Animation Techniques
  3451.  
  3452.      This chapter has presented five animation techniques:  simple animation,
  3453. XOR animation, static frame animation, dynamic frame animation, and page
  3454. flipping.  The following table summarizes their behavior.
  3455.  
  3456.                   technique      destructive?  flicker-free?
  3457.  
  3458.                   simple         yes           no
  3459.                   XOR            no            no
  3460.                   static frame   no            yes
  3461.                   dynamic frame  no            yes
  3462.                   page flipping  no            yes
  3463.  
  3464. Simple animation and XOR animation are elementary techniques that are seldom
  3465. used once you master frame animation and page flipping.
  3466.  
  3467.      As stated at the beginning of this chapter, the simple examples
  3468. presented here serve as the basis for understanding the mechanics of the
  3469. animation techniques we have discussed.  In "real world" programs, you'll
  3470. typically want to display an image using the fg_drwimage or fg_drawmap
  3471. routines instead using rudimentary images such as the rectangles in our
  3472. examples.  A helpful rule is to use pixel run maps (displayed by fg_dispfile,
  3473. fg_display, or fg_displayp) for both backgrounds and moving objects, and then
  3474. use fg_getimage or fg_getmap to retrieve the moving objects as bit-mapped
  3475. images for later display.  Of course, it is desirable to do this "behind the
  3476. scenes" work on video pages other than the visual page.
  3477.  
  3478.  
  3479. Chapter 11
  3480.  
  3481. Special Effects
  3482. 200  Fastgraph User's Guide
  3483.  
  3484.  
  3485. Overview
  3486.  
  3487.      This chapter will discuss the Fastgraph routines that help produce
  3488. special visual effects.  These include the ability to dissolve the screen
  3489. contents in small increments, scroll areas of the screen, and change the
  3490. physical origin of the screen.  The accompanying example programs illustrate
  3491. how to use these routines to produce some interesting effects.
  3492.  
  3493.  
  3494. Screen Dissolving
  3495.  
  3496.      Screen dissolving is the process of replacing the entire screen contents
  3497. in random small increments instead of all at once.  Fastgraph includes two
  3498. routines, fg_fadeout and fg_fadein, for this purpose.  The fg_fadeout routine
  3499. incrementally replaces the visual page contents with pixels of the current
  3500. color, while fg_fadein incrementally replaces the visual page contents with
  3501. the hidden page contents (that is, the page defined in the most recent call
  3502. to fg_sethpage).  Both routines accept an integer argument that defines the
  3503. delay between each incremental replacement.  A value of zero means to perform
  3504. the replacement as quickly as possible, while 1 is slightly slower, 2 is
  3505. slower yet, and so forth.  The fg_fadeout and fg_fadein routines have no
  3506. effect in text video modes.
  3507.  
  3508.      Example 11-1 shows how to use the fg_fadeout routine.  The program,
  3509. which runs in any graphics video mode, first fills the screen with a
  3510. rectangle of color 2.  After waiting for a keystroke, the program
  3511. incrementally replaces the screen contents with pixels of color 15 (the
  3512. current color index when fg_fadeout is called).  After another keystroke, the
  3513. program exits gracefully.
  3514.  
  3515.                                 Example 11-1.
  3516.  
  3517.                   #include <fastgraf.h>
  3518.                   void main(void);
  3519.  
  3520.                   void main()
  3521.                   {
  3522.                      int old_mode;
  3523.  
  3524.                      old_mode = fg_getmode();
  3525.                      fg_setmode(fg_automode());
  3526.  
  3527.                      fg_setcolor(2);
  3528.                      fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  3529.                      fg_waitkey();
  3530.  
  3531.                      fg_setcolor(15);
  3532.                      fg_fadeout(0);
  3533.                      fg_waitkey();
  3534.  
  3535.                      fg_setmode(old_mode);
  3536.                      fg_reset();
  3537.                   }
  3538.  
  3539.      Example 11-2 shows how to use the fg_fadein routine in any 320 by 200
  3540. color graphics video mode.  The program first fills the screen with a
  3541.                                              Chapter 11:  Special Effects  201
  3542.  
  3543. rectangle of color 2 and then fills video page 1 with a rectangle of color 1.
  3544. After waiting for a keystroke, the program incrementally transfers the
  3545. contents of page 1 to the visual page.  After the call to fg_fadein, both
  3546. page 0 (the visual page) and page 1 (the hidden page) will contain rectangles
  3547. of color 1 that fill the entire video page.  Finally, the program waits for
  3548. another keystroke before returning to DOS.
  3549.  
  3550.                                 Example 11-2.
  3551.  
  3552.                 #include <fastgraf.h>
  3553.                 #include <stdio.h>
  3554.                 #include <stdlib.h>
  3555.                 void main(void);
  3556.  
  3557.                 void main()
  3558.                 {
  3559.                    int new_mode, old_mode;
  3560.  
  3561.                    new_mode = fg_bestmode(320,200,2);
  3562.                    if (new_mode < 0 || new_mode == 12) {
  3563.                       printf("This program requires a 320 ");
  3564.                       printf("x 200 color graphics mode.\n");
  3565.                       exit(1);
  3566.                       }
  3567.                    old_mode = fg_getmode();
  3568.                    fg_setmode(new_mode);
  3569.                    fg_allocate(1);
  3570.                    fg_sethpage(1);
  3571.  
  3572.                    fg_setcolor(2);
  3573.                    fg_rect(0,319,0,199);
  3574.                    fg_setpage(1);
  3575.                    fg_setcolor(1);
  3576.                    fg_rect(0,319,0,199);
  3577.                    fg_waitkey();
  3578.  
  3579.                    fg_fadein(0);
  3580.                    fg_waitkey();
  3581.  
  3582.                    fg_freepage(1);
  3583.                    fg_setmode(old_mode);
  3584.                    fg_reset();
  3585.                 }
  3586.  
  3587.  
  3588.      You also can produce some appealing visual effects by replacing the
  3589. screen contents in a non-random fashion using the fg_restore or fg_transfer
  3590. routines.  For example, you could copy the hidden page contents to the visual
  3591. page with a through a series of concentric rectangular areas, each slightly
  3592. larger than the previous, until the entire screen is copied.  Another
  3593. interesting effect is to start around the screen perimeter and proceed toward
  3594. the screen center, thus producing a "snake-like" effect.  Experimenting with
  3595. such techniques may reveal other effects that suit your application.
  3596. 202  Fastgraph User's Guide
  3597.  
  3598.  
  3599. Scrolling
  3600.  
  3601.      Another useful effect is scrolling, and Fastgraph provides a routine
  3602. that performs vertical scrolling within a given region of the active video
  3603. page.  The fg_scroll routine scrolls a region defined in screen space or
  3604. character space.  It can scroll up or down and offers two types of scrolling:
  3605. circular and end-off.  In circular scrolling, rows that scroll off one edge
  3606. of the defined region appear at its opposite edge.  In end-off scrolling,
  3607. such rows are simply wind up above or below the scrolling area.  The
  3608. following diagrams illustrate the two types of scrolling.
  3609.  
  3610.                 end-off scrolling            circular scrolling
  3611.  
  3612.               before         after          before         after
  3613.  
  3614.                                C                             B
  3615.                  A                             A
  3616.  
  3617.                                A                             A
  3618.                  B                             B
  3619.  
  3620.      In these diagrams, the area bounded by the double lines is the scrolling
  3621. region, as specified in the call to fg_scroll.  Also, the scrolling direction
  3622. is assumed to be down (that is, toward the bottom of the screen), and the
  3623. number of rows to scroll is the height of the area designated B.  The number
  3624. of rows to scroll is often called the scrolling increment.
  3625.  
  3626.      For the end-off scrolling example, the scrolling operation transfers
  3627. region A downward so part of it is copied into area B.  The area C (which is
  3628. the same size as area B) at the top of the scrolling region is filled with
  3629. pixels of the current color index (as defined in the most recent call to
  3630. fg_setcolor), and the original contents of area B are lost.  The circular
  3631. scrolling example also copies region A downward into the original area B.
  3632. Unlike end-off scrolling, however, circular scrolling preserves the area B by
  3633. copying it to the opposite edge of the scrolling region.
  3634.  
  3635.      The fg_scroll routine takes six arguments.  The first four define the
  3636. scrolling region in the order minimum x coordinate, maximum x coordinate,
  3637. minimum y coordinate, and maximum y coordinate.  In graphics video modes, the
  3638. x coordinates are extended by byte boundaries (see page 174) if needed.  The
  3639. fifth argument is the scrolling increment.  It specifies the number of rows
  3640. to scroll.  If it is positive, the scrolling direction is toward the bottom
  3641. of the screen; if it is negative, the scrolling direction is toward the top
  3642. of the screen.  The sixth and final argument specifies the scroll type.  If
  3643. this value is zero, the scroll will be circular; if it is any other value,
  3644. the scroll will be end-off.  If the scroll type is circular, Fastgraph will
  3645. use the hidden page (as defined in the most recent call to fg_sethpage) as a
  3646. workspace (more specifically, the area bounded by the scrolling region
  3647. extremes on the hidden page will be used).  We'll now present three example
  3648. programs that use the fg_scroll routine.
  3649.  
  3650.      Example 11-3 runs in any 320 by 200 graphics video mode.  The program
  3651. displays two lines of text ("line one" and "line two") in the upper left
  3652. corner of the screen against a white background.  It then uses the fg_scroll
  3653. routine to move the second line down four pixel rows using an end-off scroll.
  3654. After waiting for a keystroke, the program again uses fg_scroll to move the
  3655.                                              Chapter 11:  Special Effects  203
  3656.  
  3657. text back to its original position.  Note especially how the fg_setcolor
  3658. routine appears before the first call to fg_scroll to replace the "scrolled
  3659. off" rows with pixels of color 15, thus preserving the white background.
  3660.  
  3661.                                 Example 11-3.
  3662.  
  3663.                 #include <fastgraf.h>
  3664.                 #include <stdio.h>
  3665.                 #include <stdlib.h>
  3666.                 void main(void);
  3667.  
  3668.                 void main()
  3669.                 {
  3670.                    int new_mode, old_mode;
  3671.  
  3672.                    new_mode = fg_bestmode(320,200,1);
  3673.                    if (new_mode < 0 || new_mode == 12) {
  3674.                       printf("This program requires a 320 ");
  3675.                       printf("x 200 color graphics mode.\n");
  3676.                       exit(1);
  3677.                       }
  3678.                    old_mode = fg_getmode();
  3679.                    fg_setmode(new_mode);
  3680.  
  3681.                    fg_setcolor(15);
  3682.                    fg_rect(0,319,0,199);
  3683.                    fg_setcolor(10);
  3684.                    fg_text("line one",8);
  3685.                    fg_locate(1,0);
  3686.                    fg_text("line two",8);
  3687.                    fg_waitkey();
  3688.  
  3689.                    fg_setcolor(15);
  3690.                    fg_scroll(0,63,8,15,4,1);
  3691.                    fg_waitkey();
  3692.                    fg_scroll(0,63,12,19,-4,1);
  3693.                    fg_waitkey();
  3694.  
  3695.                    fg_setmode(old_mode);
  3696.                    fg_reset();
  3697.                 }
  3698.  
  3699.      Example 11-4 is similar to example 11-3, but it runs in the 80-column
  3700. color text mode (mode 3).  In text modes, we cannot scroll half a character
  3701. row (four pixels) as in example 11-3, so the program scrolls the minimum one
  3702. row instead.
  3703.  
  3704.                                 Example 11-4.
  3705.  
  3706.                          #include <fastgraf.h>
  3707.                          void main(void);
  3708.  
  3709.                          void main()
  3710.                          {
  3711.                             int old_mode;
  3712.  
  3713. 204  Fastgraph User's Guide
  3714.  
  3715.                             old_mode = fg_getmode();
  3716.                             fg_setmode(3);
  3717.                             fg_cursor(0);
  3718.  
  3719.                             fg_setcolor(7);
  3720.                             fg_rect(0,79,0,24);
  3721.                             fg_setattr(10,7,0);
  3722.                             fg_text("line one",8);
  3723.                             fg_locate(1,0);
  3724.                             fg_text("line two",8);
  3725.                             fg_waitkey();
  3726.  
  3727.                             fg_setcolor(7);
  3728.                             fg_scroll(0,7,1,1,1,1);
  3729.                             fg_waitkey();
  3730.                             fg_scroll(0,7,2,2,-1,1);
  3731.                             fg_waitkey();
  3732.  
  3733.                             fg_setmode(old_mode);
  3734.                             fg_reset();
  3735.                          }
  3736.  
  3737.      Example 11-5, the final scrolling example, demonstrates a circular
  3738. scroll.  The program runs in any 320 by 200 color graphics video mode; note
  3739. the use of video page 1 for the workspace required when the fg_scroll routine
  3740. performs a circular scroll.  The program first fills the screen with a light
  3741. blue rectangle (cyan in CGA), displays a smaller white rectangle in the
  3742. center of the screen, and then uses fg_move, fg_draw, and fg_paint to display
  3743. a light green star (magenta in CGA) within the white rectangle.  The program
  3744. executes a while loop to scroll the star upward in four pixel increments.
  3745. Because the scroll is circular, rows of the star that "scroll off" the top
  3746. edge of the white rectangle (whose height is the same as the scrolling
  3747. region) reappear at its bottom edge.  The use of fg_waitfor within the loop
  3748. simply slows down the scroll.  The scrolling continues until any key is
  3749. pressed.
  3750.  
  3751.                                 Example 11-5.
  3752.  
  3753.                 #include <conio.h>
  3754.                 #include <fastgraf.h>
  3755.                 #include <stdio.h>
  3756.                 #include <stdlib.h>
  3757.                 void main(void);
  3758.  
  3759.                 void main()
  3760.                 {
  3761.                    int new_mode, old_mode;
  3762.  
  3763.                    new_mode = fg_bestmode(320,200,2);
  3764.                    if (new_mode < 0 || new_mode == 12) {
  3765.                       printf("This program requires a 320 ");
  3766.                       printf("x 200 color graphics mode.\n");
  3767.                       exit(1);
  3768.                       }
  3769.                    old_mode = fg_getmode();
  3770.                    fg_setmode(new_mode);
  3771.  
  3772.                                              Chapter 11:  Special Effects  205
  3773.                    fg_allocate(1);
  3774.                    fg_sethpage(1);
  3775.  
  3776.                    fg_setcolor(9);
  3777.                    fg_rect(0,319,0,199);
  3778.                    fg_setcolor(15);
  3779.                    fg_rect(132,188,50,150);
  3780.  
  3781.                    fg_setcolor(10);
  3782.                    fg_move(160,67);
  3783.                    fg_draw(175,107);
  3784.                    fg_draw(140,82);
  3785.                    fg_draw(180,82);
  3786.                    fg_draw(145,107);
  3787.                    fg_draw(160,67);
  3788.                    fg_paint(160,77);
  3789.                    fg_paint(150,87);
  3790.                    fg_paint(160,87);
  3791.                    fg_paint(170,87);
  3792.                    fg_paint(155,97);
  3793.                    fg_paint(165,97);
  3794.  
  3795.                    while (kbhit() == 0) {
  3796.                       fg_waitfor(1);
  3797.                       fg_scroll(136,184,50,150,-4,0);
  3798.                       }
  3799.                    fg_waitkey();
  3800.  
  3801.                    fg_freepage(1);
  3802.                    fg_setmode(old_mode);
  3803.                    fg_reset();
  3804.                 }
  3805.  
  3806.  
  3807. Changing the Screen Origin
  3808.  
  3809.      Fastgraph includes two routines for changing the screen origin.  By
  3810. changing the screen origin, we simply mean defining the (x,y) coordinate of
  3811. the upper left corner of the display area.  The fg_pan routine performs this
  3812. function in screen space, while the fg_panw routine does in world space.
  3813. Neither routine changes the graphics cursor position.
  3814.  
  3815.      Each of these routines has two arguments that specify the x and y
  3816. coordinates of the screen origin.  For the fg_pan routine, the arguments are
  3817. integer quantities.  For the fg_panw routine, they are floating point
  3818. quantities.
  3819.  
  3820.      In the native EGA and VGA graphics modes (modes 13 through 18), you can
  3821. set the screen origin to any (x,y) coordinate position (that is, to any
  3822. pixel).  In the other graphics modes, certain restrictions exist, as imposed
  3823. by specific video hardware.  These constraints limit the coordinate positions
  3824. that can be used as the screen origin.  Fastgraph compensates for these
  3825. restrictions by reducing the specified x and y coordinates to values that are
  3826. acceptable to the current video mode, as shown in the following table.
  3827. 206  Fastgraph User's Guide
  3828.  
  3829.  
  3830.                            x will be reduced  y will be reduced
  3831.                video mode  to a multiple of:  to a multiple of:
  3832.  
  3833.                   4, 5              8                  2
  3834.                     6              16                  2
  3835.                     9               4                  4
  3836.                    11               8                  4
  3837.                    12               4                2 or 3
  3838.                 19 to 23            4                  1
  3839.  
  3840. For example, in modes 4 and 5, the x coordinate will be reduced to a multiple
  3841. of 8 pixels, and the y coordinate will be reduced to a multiple of 2 pixels.
  3842. In the Hercules low resolution mode (mode 12), the y coordinate reduction
  3843. depends on whether or not the specified pixel row is scan doubled.
  3844.  
  3845.      Example 11-6 shows a useful effect that can be made with the fg_pan or
  3846. fg_panw routines.  This program uses the fg_automode routine to select a
  3847. video mode and then draws an unfilled rectangle in color 15 (bright white).
  3848. The top and bottom sides of the rectangle are intentionally drawn just
  3849. smaller than the physical screen size.  After waiting for a keystroke, the
  3850. program uses a for loop to make the rectangle jiggle up and down.  The
  3851. rectangle moves because the fg_pan routine is called inside the loop to
  3852. switch the screen origin between the rectangle's upper left corner and the
  3853. original origin.  Note also the use of the fg_waitfor routine to cause slight
  3854. delays after each call to fg_pan.  If we didn't use fg_waitfor, the changing
  3855. of the origin would occur so rapidly we wouldn't notice the effect.  Finally,
  3856. the program restores the original video mode and screen attributes before
  3857. returning to DOS.
  3858.  
  3859.                                 Example 11-6.
  3860.  
  3861.                  #include <fastgraf.h>
  3862.                  #include <stdio.h>
  3863.                  #include <stdlib.h>
  3864.                  void main(void);
  3865.  
  3866.                  #define DELAY 2
  3867.                  #define JUMP  4
  3868.  
  3869.                  void main()
  3870.                  {
  3871.                     int i;
  3872.                     int old_mode;
  3873.  
  3874.                     old_mode = fg_getmode();
  3875.                     fg_setmode(fg_automode());
  3876.  
  3877.                     fg_setcolor(15);
  3878.                     fg_move(0,JUMP);
  3879.                     fg_draw(fg_getmaxx(),JUMP);
  3880.                     fg_draw(fg_getmaxx(),fg_getmaxy()-JUMP);
  3881.                     fg_draw(0,fg_getmaxy()-JUMP);
  3882.                     fg_draw(0,JUMP);
  3883.                     fg_waitkey();
  3884.  
  3885.                                              Chapter 11:  Special Effects  207
  3886.  
  3887.                     for (i = 0; i < 6; i++) {
  3888.                        fg_pan(0,JUMP);
  3889.                        fg_waitfor(DELAY);
  3890.                        fg_pan(0,0);
  3891.                        fg_waitfor(DELAY);
  3892.                        }
  3893.  
  3894.                     fg_setmode(old_mode);
  3895.                     fg_reset();
  3896.                  }
  3897.  
  3898.      The real power of the fg_pan routine becomes clear when it is used with
  3899. the fg_resize routine to perform smooth panning.  Recall from Chapter 7 that
  3900. fg_resize changes the video page dimensions in native EGA graphics modes
  3901. (modes 13 through 16), native VGA graphics modes (modes 17 and 18), and the
  3902. extended VGA graphics modes (modes 20 through 23).  We'll now present an
  3903. example that shows how to use these two routines to perform panning in the
  3904. low-resolution EGA graphics mode (mode 13).  The method it uses also would
  3905. work in any mode that supports video page resizing.
  3906.  
  3907.      Example 11-7 begins by establishing the video mode and then immediately
  3908. calls fg_resize to increase the video page size to 640 x 400 pixels.  Thus,
  3909. the video page is now four times its original size.  Following this, the
  3910. program fills the page (the entire page, not just what is displayed) with a
  3911. bright green rectangle with a white border around it.  It then displays the
  3912. message "Press arrow keys to pan" as close as possible to the center of the
  3913. page.
  3914.  
  3915.      The main part of the program is a loop that accepts keystrokes and then
  3916. calls fg_pan to perform the panning one pixel at a time.  When you press any
  3917. of the four arrow keys, the program adjusts the x and y coordinates for the
  3918. screen origin as directed.  For example, pressing the up arrow key scrolls
  3919. the screen upward one pixel.  Note that when we reach the edge of the video
  3920. page, the program prevents further scrolling in that direction.  This process
  3921. continues until you press the Esc key, at which time the program restores the
  3922. original video mode and screen attributes before exiting.
  3923.  
  3924.                                 Example 11-7.
  3925.  
  3926.                   #include <fastgraf.h>
  3927.                   void main(void);
  3928.  
  3929.                   void main()
  3930.                   {
  3931.                      unsigned char key, aux;
  3932.                      int old_mode;
  3933.                      int x, y;
  3934.  
  3935.                      old_mode = fg_getmode();
  3936.                      fg_setmode(13);
  3937.                      fg_resize(640,400);
  3938.  
  3939.                      fg_setcolor(2);
  3940.                      fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  3941.                      fg_setcolor(15);
  3942.                      fg_box(0,fg_getmaxx(),0,fg_getmaxy());
  3943.  
  3944. 208  Fastgraph User's Guide
  3945.  
  3946.                      fg_locate(24,28);
  3947.                      fg_text("Press arrow keys to pan.",24);
  3948.  
  3949.                      x = 0;
  3950.                      y = 0;
  3951.  
  3952.                      do {
  3953.                         fg_getkey(&key,&aux);
  3954.                         if (aux == 72 && y < 200)
  3955.                            y++;
  3956.                         else if (aux == 75 && x < 320)
  3957.                            x++;
  3958.                         else if (aux == 77 && x > 0)
  3959.                            x--;
  3960.                         else if (aux == 80 && y > 0)
  3961.                            y--;
  3962.                         fg_pan(x,y);
  3963.                      } while (key != 27);
  3964.  
  3965.                      fg_setmode(old_mode);
  3966.                      fg_reset();
  3967.                   }
  3968.  
  3969.  
  3970.  
  3971. Summary of Special Effects Routines
  3972.  
  3973.      This section summarizes the functional descriptions of the Fastgraph
  3974. routines presented in this chapter.  More detailed information about these
  3975. routines, including their arguments and return values, may be found in the
  3976. Fastgraph Reference Manual.
  3977.  
  3978.      FG_FADEIN incrementally replaces the visual page contents with the
  3979. hidden page contents.  This routine has no effect in text video modes.
  3980.  
  3981.      FG_FADEOUT incrementally replaces the visual page contents with pixels
  3982. of the current color.  This routine has no effect in text video modes.
  3983.  
  3984.      FG_PAN changes the screen origin (the upper left corner of the screen)
  3985. to the specified screen space coordinates.  This routine has no effect in
  3986. text video modes.
  3987.  
  3988.      FG_PANW is the world space version of the fg_pan routine.
  3989.  
  3990.      FG_RESIZE changes the dimensions of a video page in EGA and VGA graphics
  3991. modes.
  3992.  
  3993.      FG_SCROLL vertically scrolls a region of the active video page.  The
  3994. scrolling may be done either up or down, using either an end-off or circular
  3995. method.  Circular scrolling uses part of the hidden page as a temporary
  3996. workspace.
  3997.  
  3998.  
  3999. Chapter 12
  4000.  
  4001. Input Device Support
  4002. 210  Fastgraph User's Guide
  4003.  
  4004.  
  4005. Overview
  4006.  
  4007.      The selection of application input devices is an important part of
  4008. designing a program for the IBM PC and PS/2 family of systems.  The keyboard
  4009. and mouse are very popular, and in fact more and more applications,
  4010. especially those that use a graphical interface, actually require a mouse to
  4011. use the product.  Another input device, primarily used in entertainment
  4012. software, is the joystick.  Although not as popular as the mouse, the
  4013. joystick nevertheless can simplify the use of certain applications.
  4014. Fastgraph provides support for these three types of input devices, and this
  4015. chapter will discuss this in detail.
  4016.  
  4017.  
  4018. Keyboard Support
  4019.  
  4020.      Fastgraph's keyboard support includes routines to read keystrokes, check
  4021. the state of certain keys, and set the state of these keys.  These routines
  4022. are independent of the other parts of Fastgraph and thus do not require that
  4023. you call fg_setmode.  All keyboard-related routines work in text and graphics
  4024. video modes.
  4025.  
  4026.      The IBM PC and PS/2 keyboards produce two types of character codes --
  4027. standard codes and extended codes (extended codes are sometimes called
  4028. auxiliary codes).  The standard codes correspond to the 128 characters in the
  4029. ASCII character set.  In general, pressing keys on the main part of the
  4030. keyboard, or on the numeric keypad with NumLock turned on, will generate a
  4031. standard code.  The 128 extended codes are specific to the IBM PC and PS/2
  4032. keyboards.  Some common keystrokes that produce extended codes are keys on
  4033. the numeric keypad with NumLock turned off, the function keys, or pressing
  4034. Alt with another key.  The following tables show the standard and extended
  4035. keyboard codes.
  4036.  
  4037.                        Table of standard keyboard codes
  4038.  
  4039.           key     code   key     code   key     code   key     code
  4040.  
  4041.           (none)    0    space    32    @        64    `        96
  4042.           Ctrl+A    1    !        33    A        65    a        97
  4043.           Ctrl+B    2    "        34    B        66    b        98
  4044.           Ctrl+C    3    #        35    C        67    c        99
  4045.           Ctrl+D    4    $        36    D        68    d       100
  4046.           Ctrl+E    5    %        37    E        69    e       101
  4047.           Ctrl+F    6    &        38    F        70    f       102
  4048.           Ctrl+G    7    '        39    G        71    g       103
  4049.           Ctrl+H    8    (        40    H        72    h       104
  4050.           Ctrl+I    9    )        41    I        73    i       105
  4051.           Ctrl+J   10    *        42    J        74    j       106
  4052.           Ctrl+K   11    +        43    K        75    k       107
  4053.           Ctrl+L   12    ,        44    L        76    l       108
  4054.           Ctrl+M   13    -        45    M        77    m       109
  4055.           Ctrl+N   14    .        46    N        78    n       110
  4056.           Ctrl+O   15    /        47    O        79    o       111
  4057.           Ctrl+P   16    0        48    P        80    p       112
  4058.           Ctrl+Q   17    1        49    Q        81    q       113
  4059.           Ctrl+R   18    2        50    R        82    r       114
  4060.  
  4061.                                         Chapter 12:  Input Device Support  211
  4062.  
  4063.           Ctrl+S   19    3        51    S        83    s       115
  4064.           Ctrl+T   20    4        52    T        84    t       116
  4065.           Ctrl+U   21    5        53    U        85    u       117
  4066.           Ctrl+V   22    6        54    V        86    v       118
  4067.           Ctrl+W   23    7        55    W        87    w       119
  4068.           Ctrl+X   24    8        56    X        88    x       120
  4069.           Ctrl+Y   25    9        57    Y        89    y       121
  4070.           Ctrl+Z   26    :        58    Z        90    z       122
  4071.           Ctrl+[   27    ;        59    [        91    {       123
  4072.           Ctrl+\   28    <        60    \        92    |       124
  4073.           Ctrl+]   29    =        61    ]        93    }       125
  4074.           Ctrl+^   30    >        62    ^        94    ~       126
  4075.           Ctrl+-   31    ?        63    _        95    Ctrl+BS 127
  4076.  
  4077.  
  4078.                        Table of extended keyboard codes
  4079.  
  4080.               code        key
  4081.  
  4082.                3          Ctrl+@
  4083.               15          Shift+Tab (back tab)
  4084.               16-25       Alt+Q to Alt+P (top row of letters)
  4085.               30-38       Alt+A to Alt+L (middle row of letters)
  4086.               44-50       Alt+Z to Alt+M (bottom row of letters)
  4087.               59-68       F1 to F10
  4088.               71          Home
  4089.               72          up arrow
  4090.               73          PgUp
  4091.               75          left arrow
  4092.               77          right arrow
  4093.               79          End
  4094.               80          down arrow
  4095.               81          PgDn
  4096.               82          Ins
  4097.               83          Del
  4098.               84-93       Shift+F1 to Shift+F10
  4099.               94-103      Ctrl+F1 to Ctrl+F10
  4100.               104-113     Alt+F1 to Alt+F10
  4101.               114         Ctrl+PrtSc
  4102.               115         Ctrl+left arrow
  4103.               116         Ctrl+right arrow
  4104.               117         Ctrl+End
  4105.               118         Ctrl+PgDn
  4106.               119         Ctrl+Home
  4107.               120-131     Alt+1 to Alt+= (top row of keys)
  4108.               132         Ctrl+PgUp
  4109.  
  4110. In addition, four keys generate the same standard codes as other control key
  4111. combinations.  These keys are:
  4112.  
  4113.                            key       same as  code
  4114.  
  4115.                            Backspace Ctrl+H    8
  4116.                            Tab       Ctrl+I    9
  4117.                            Enter     Ctrl+M   13
  4118.                            Escape    Ctrl+[   27
  4119.  
  4120. 212  Fastgraph User's Guide
  4121.  
  4122.      The CapsLock, NumLock, and ScrollLock keys do not generate a standard or
  4123. extended code when pressed.  Instead, they toggle between off and on states.
  4124.  
  4125. Reading Keystrokes
  4126.  
  4127.      When you press a key or key combination, the standard or extended code
  4128. representing that keystroke is stored in the ROM BIOS keyboard buffer.  This
  4129. buffer can hold up to 16 keystrokes and thus provides a type-ahead
  4130. capability.  Fastgraph includes three routines for reading keystroke
  4131. information from the keyboard buffer.  The fg_getkey routine reads the next
  4132. item in the keyboard buffer if one is available (that is, if a key has been
  4133. pressed).  If the keyboard buffer is empty (meaning no key has been pressed),
  4134. fg_getkey waits for a keystroke and then reports information about it.
  4135. Another routine, fg_intkey, reads the next keystroke from the keyboard buffer
  4136. if one is available.  If the keyboard buffer is empty, fg_intkey immediately
  4137. returns and reports this condition.  The fg_intkey routine is useful when a
  4138. program must continue performing a task until a key is pressed.  We've
  4139. already seen the third routine, fg_waitkey, which flushes the keyboard buffer
  4140. and then waits for another keystroke.  Unlike fg_getkey and fg_intkey,
  4141. fg_waitkey does not return any keystroke information.  It is most useful in
  4142. "press any key to continue" situations.
  4143.  
  4144.      Both the fg_getkey and fg_intkey routines require two one-byte arguments
  4145. passed by reference.  If the keystroke is represented by a standard keyboard
  4146. code, fg_getkey and fg_intkey return its code in the first argument and set
  4147. the second argument to zero.  Similarly, if the keystroke generates an
  4148. extended code, the routines return its code in the second argument and set
  4149. the first argument to zero.  If the fg_intkey routine detects an empty
  4150. keyboard buffer, it sets both arguments to zero.
  4151.  
  4152.      Example 12-1 is a simple program that uses the fg_getkey routine.  It
  4153. solicits keystrokes and then displays the two values returned by fg_getkey,
  4154. one of which will always be zero.  The variable key receives the key's
  4155. standard code, while aux receives its extended code.  Note that fg_getkey is
  4156. the only Fastgraph routine in the program; this can be done because the
  4157. keyboard support routines are logically independent from the rest of
  4158. Fastgraph.  The program returns to DOS when you press the Escape key.
  4159.  
  4160.                                 Example 12-1.
  4161.  
  4162.                #include <fastgraf.h>
  4163.                #include <stdio.h>
  4164.                void main(void);
  4165.  
  4166.                #define ESC 27
  4167.  
  4168.                void main()
  4169.                {
  4170.                   unsigned char key, aux;
  4171.  
  4172.                   do {
  4173.                      fg_getkey(&key,&aux);
  4174.                      printf("key = %3d  aux = %3d\n",key,aux);
  4175.                      }
  4176.                   while (key != ESC);
  4177.                }
  4178.  
  4179.                                         Chapter 12:  Input Device Support  213
  4180.  
  4181.      Example 12-2 reads keystrokes using the fg_intkey routine at half-second
  4182. intervals (18 fg_waitfor units equals one second).  As in the previous
  4183. example, the program displays the standard and extended codes for each
  4184. keystroke.  However, example 12-2 will continuously execute the while loop
  4185. even if no keystrokes are available, in which case the key and aux values
  4186. will both be zero.  The program returns to DOS when you press the Escape key.
  4187.  
  4188.                                 Example 12-2.
  4189.  
  4190.                #include <fastgraf.h>
  4191.                #include <stdio.h>
  4192.                void main(void);
  4193.  
  4194.                #define ESC 27
  4195.  
  4196.                void main()
  4197.                {
  4198.                   unsigned char key, aux;
  4199.  
  4200.                   do {
  4201.                      fg_waitfor(9);
  4202.                      fg_intkey(&key,&aux);
  4203.                      printf("key = %3d  aux = %3d\n",key,aux);
  4204.                      }
  4205.                   while (key != ESC);
  4206.                }
  4207.  
  4208.  
  4209.      When you use fg_intkey in a "tight" loop that does little else, you
  4210. should force a small delay within the loop by calling fg_waitfor as in
  4211. example 12-2.  Typically a delay of one or two clock ticks is enough.
  4212. Without this delay, the BIOS may not be able to handle all keyboard activity,
  4213. and thus some keystrokes may not be available to your program.
  4214.  
  4215.  
  4216. Testing and Setting Key States
  4217.  
  4218.      As mentioned earlier, the CapsLock, NumLock, and ScrollLock keys do not
  4219. generate a standard or extended code when pressed but instead toggle between
  4220. off and on states.  Fastgraph includes routines for checking the state of
  4221. these keys, as well as setting the state of the CapsLock and NumLock keys.
  4222.  
  4223.      The Fastgraph routines fg_capslock, fg_numlock, and fg_scrlock
  4224. respectively read the state of the CapsLock, NumLock, and ScrollLock keys.
  4225. Each routine has no arguments and returns the key state as its function
  4226. value.  A return value of 0 means the associated key is in the off state,
  4227. while 1 indicates the key is in the on state.  If the keyboard does not have
  4228. a ScrollLock key, fg_scrlock considers the key off and returns a value of
  4229. zero.
  4230.  
  4231.      Example 12-3 is a simple program that uses the fg_capslock, fg_numlock,
  4232. and fg_scrlock routines to print messages describing the current state of
  4233. these three keys.
  4234. 214  Fastgraph User's Guide
  4235.  
  4236.                                 Example 12-3.
  4237.  
  4238.                     #include <fastgraf.h>
  4239.                     #include <stdio.h>
  4240.                     void main(void);
  4241.  
  4242.                     void main()
  4243.                     {
  4244.                        if (fg_capslock())
  4245.                           printf("CapsLock is on.\n");
  4246.                        else
  4247.                           printf("CapsLock is off.\n");
  4248.  
  4249.                        if (fg_numlock())
  4250.                           printf("NumLock is on.\n");
  4251.                        else
  4252.                           printf("NumLock is off.\n");
  4253.  
  4254.                        if (fg_scrlock())
  4255.                           printf("ScrollLock is on.\n");
  4256.                        else
  4257.                           printf("ScrollLock is off.\n");
  4258.                     }
  4259.  
  4260.      You also can set the state of the CapsLock and NumLock keys within a
  4261. program.  Fastgraph includes two routines, fg_setcaps and fg_setnum, for this
  4262. purpose.  Each routine requires an integer argument that specifies the new
  4263. key state.  If the argument value is 0, the key will be turned off; if the
  4264. value is 1, the key will be turned on.  Example 12-4 uses fg_setcaps and
  4265. fg_setnum to turn off CapsLock and NumLock.
  4266.  
  4267.                                 Example 12-4.
  4268.  
  4269.                             #include <fastgraf.h>
  4270.                             void main(void);
  4271.  
  4272.                             void main()
  4273.                             {
  4274.                                fg_setcaps(0);
  4275.                                fg_setnum(0);
  4276.                             }
  4277.  
  4278.      On most keyboards, changing key states with fg_setcaps or fg_setnum also
  4279. will change the keyboard state light to reflect the new key state.  However,
  4280. some older keyboards, especially when used on PC, PC/XT, or Tandy 1000
  4281. systems, do not update the state light.  This makes the state light
  4282. inconsistent with the true key state.
  4283.  
  4284.  
  4285. Mouse Support
  4286.  
  4287.      The mouse is a very popular input and pointing device, especially in
  4288. graphically-oriented programs.  Fastgraph contains several routines to
  4289. support mice.  These routines perform such tasks as mouse initialization,
  4290. controlling and defining the mouse cursor, and reporting information about
  4291. the mouse position and button status.
  4292.                                         Chapter 12:  Input Device Support  215
  4293.  
  4294.      The underlying software that controls the mouse is called the mouse
  4295. driver.  Fastgraph's mouse support routines provide a high-level interface to
  4296. this driver.  The Microsoft Mouse and its accompanying mouse driver have
  4297. become an industry standard, and other manufacturers of mice have also made
  4298. their mouse drivers Microsoft compatible.  For this reason, the Fastgraph
  4299. mouse support routines assume you are using a Microsoft or compatible mouse
  4300. driver.
  4301.  
  4302.      Unfortunately, not all mouse drivers are created equal.  That is, some
  4303. drivers are not Microsoft compatible, even though they may be advertised as
  4304. such.  In some cases, these incompatibilities are rather trivial, but others
  4305. are significant.  For example, early versions of some third party mouse
  4306. drivers had real problems in the EGA graphics modes.  The Microsoft mouse
  4307. driver, the Logitech mouse driver (version 3.2 or above), and the DFI mouse
  4308. driver (version 3.00 or above) are known to work well with Fastgraph's mouse
  4309. support routines.  Any other Microsoft compatible mouse driver also should
  4310. work properly.
  4311.  
  4312.  
  4313. Initializing the Mouse
  4314.  
  4315.      There are two steps required to use Fastgraph's mouse support routines
  4316. within an application program.  First, you must install the mouse driver.
  4317. This is done before running the application, typically by entering the
  4318. command MOUSE at the DOS command prompt.  Second, you must use the Fastgraph
  4319. routine fg_mouseini to initialize the mouse within the program.
  4320.  
  4321.      The fg_mouseini routine has no arguments and returns a "success or
  4322. failure" indicator as its function value.  If the return value is -1, it
  4323. means fg_mouseini could not initialize the mouse (either because the mouse
  4324. driver is not installed, or the driver is installed but the mouse is
  4325. physically disconnected).  The fg_mouseini routine also will return -1 when
  4326. used in the extended VGA graphics video modes (modes 20 through 23) because
  4327. there is no mouse support available in these video modes.  If fg_mouseini
  4328. returns a positive integer value, then the mouse initialization was
  4329. successful.  The value itself indicates the number of buttons (either 2 or 3)
  4330. on the mouse.  If you don't call fg_mouseini, or if fg_mouseini can't
  4331. initialize the mouse, none of Fastgraph's other mouse support routines will
  4332. have any effect.(3)
  4333.  
  4334.      Example 12-5 illustrates how to initialize the mouse.  Unlike the
  4335. keyboard support routines, Fastgraph's mouse support routines require that
  4336. fg_setmode first be called.  In this example, we simply pass fg_setmode the
  4337. value -1 to initialize Fastgraph for whatever video mode is in effect when we
  4338. run the program.  The program then calls fg_mouseini and prints a message
  4339. indicating whether or not the initialization was successful.  If it was, the
  4340. message includes the number of buttons on the mouse.
  4341.  
  4342.                                 Example 12-5.
  4343.  
  4344.                #include <fastgraf.h>
  4345.  
  4346. ____________________
  4347.      (3) If you use another mouse library or communicate directly with the
  4348. mouse driver, you must still call fg_mouseini if your program runs in modes
  4349. 13 through  18.  Otherwise, Fastgraph won't know that your program is using
  4350. a mouse and may display graphics incorrectly.
  4351. 216  Fastgraph User's Guide
  4352.  
  4353.                #include <stdio.h>
  4354.                void main(void);
  4355.  
  4356.                void main()
  4357.                {
  4358.                   int status;
  4359.  
  4360.                   fg_setmode(-1);
  4361.                   status = fg_mouseini();
  4362.  
  4363.                   if (status < 0)
  4364.                      printf("Mouse not available.\n");
  4365.                   else
  4366.                      printf("%d button mouse found.\n",status);
  4367.                }
  4368.  
  4369.      You should be aware that certain mouse drivers do not fully initialize
  4370. the mouse when a program changes video modes.  This problem most frequently
  4371. occurs when you restore the original video mode at the end of a program that
  4372. has called fg_mouseini.  When changing video modes, you must first make the
  4373. mouse cursor invisible (this is described in the next section), change the
  4374. video mode, and then call fg_mouseini again to initialize the mouse for the
  4375. new video mode.
  4376.  
  4377.  
  4378. Controlling the Mouse Cursor
  4379.  
  4380.      The mouse cursor indicates the current position of the mouse.  By
  4381. default, the cursor is a small white arrow in graphics modes and a one-
  4382. character rectangle in text modes.  After you use fg_mouseini to initialize
  4383. the mouse, the mouse cursor is invisible.  To make it visible, you must use
  4384. the fg_mousevis routine.  This routine has a single integer argument that
  4385. defines the mouse cursor visibility.  If it is 0, the mouse cursor will be
  4386. invisible; if it is 1, the mouse cursor becomes visible.
  4387.  
  4388.      If the mouse cursor is in an area of the screen that is being updated,
  4389. or if it moves into this area during the update process, you must make the
  4390. mouse cursor invisible.  Additionally, when performing any video output in
  4391. the native EGA and VGA graphics modes (modes 13 through 18), you also must
  4392. make the mouse cursor invisible.  Instead of checking for these conditions,
  4393. it is more convenient and efficient to make the mouse cursor invisible during
  4394. all screen updates and then make it visible again when the updating is
  4395. finished.  Finally, you must make the mouse cursor invisible whenever you
  4396. change the visual page number with fg_setvpage.
  4397.  
  4398.      After you initialize the mouse, the cursor is positioned in the center
  4399. of the screen.  Moving the mouse of course changes the cursor position, but
  4400. you also can position the mouse cursor with the Fastgraph routine
  4401. fg_mousemov.  This routine has two arguments that specify the new horizontal
  4402. and vertical cursor position.  The position is expressed in screen space
  4403. units for graphics modes, while it is expressed in character cells for text
  4404. modes.  The fg_mousemov routine moves the cursor whether or not it is
  4405. visible.
  4406.  
  4407.      Sometimes it is useful to restrict the mouse cursor to a specific area
  4408. of the screen.  The Fastgraph routine fg_mouselim prevents the mouse cursor
  4409. from moving outside the specified rectangular area.  It requires four
  4410.                                         Chapter 12:  Input Device Support  217
  4411.  
  4412. arguments that specify the minimum horizontal coordinate, maximum horizontal
  4413. coordinate, minimum vertical coordinate, and maximum vertical coordinate of
  4414. this area.  Again, the coordinates are expressed in screen space units for
  4415. graphics modes and character cells for text modes.
  4416.  
  4417.      One of the most important functions of the mouse driver is to translate
  4418. the horizontal and vertical mouse movements into a position on the screen.
  4419. The mouse reports these movements to the mouse driver in units called mickeys
  4420. (one mickey is about 1/200 of an inch).  By default, moving the mouse 8
  4421. mickeys in the horizontal direction moves the mouse cursor one horizontal
  4422. pixel.  Similarly, moving the mouse 16 mickeys vertically moves the cursor
  4423. one vertical pixel.  Fastgraph provides a routine named fg_mousespd that can
  4424. change these values, which effectively allows you to control the speed at
  4425. which the mouse cursor moves relative to the movement of the mouse itself.
  4426. The fg_mousespd routine requires two arguments that define the number of
  4427. mickeys required for eight pixels of mouse cursor movement.  The first
  4428. argument specifies this for the horizontal direction, and the second for the
  4429. vertical direction.
  4430.  
  4431.      Example 12-6, which runs in any graphics mode, demonstrates the
  4432. fg_mousevis, fg_mousemov, fg_mouselim, and fg_mousespd routines.  The program
  4433. first establishes the video mode, initializes the mouse, and fills the screen
  4434. with a white rectangle.  Next, the program calls fg_mousevis to make the
  4435. mouse cursor visible and then calls fg_mouselim to restrict the mouse cursor
  4436. to an area one-fourth the size of the screen, centered in the middle of the
  4437. screen.  At this point you should move the mouse cursor around the screen to
  4438. see the effect of fg_mouselim and note the speed at which the cursor moves
  4439. relative to the mouse itself.  The program continues when you press any key.
  4440.  
  4441.      The program then uses fg_mousemov to move the mouse cursor to each
  4442. corner of the region established by fg_mouselim.  The call to fg_waitfor
  4443. keeps the cursor in each corner for two seconds, unless you move the mouse.
  4444. Note how the program tries to move the mouse cursor to each corner of the
  4445. screen, but since doing so would move the cursor outside the defined region
  4446. of movement, fg_mousemov just positions the cursor at the nearest point
  4447. possible within this region.  The last call to fg_mousemov moves the cursor
  4448. back to the middle of the screen.  After doing this, the program calls
  4449. fg_mousespd to change the mouse cursor speed.  The values passed to
  4450. fg_mousespd (16 and 32) are twice the defaults and therefore make you move
  4451. the mouse twice as far as before to move the mouse cursor the same distance.
  4452. When you run the program, compare the mouse sensitivity to the original
  4453. speed.  After a keystroke, the program returns to DOS.
  4454.  
  4455.                                 Example 12-6.
  4456.  
  4457.                #include <fastgraf.h>
  4458.                #include <stdio.h>
  4459.                #include <stdlib.h>
  4460.                void main(void);
  4461.  
  4462.                void main()
  4463.                {
  4464.                   int maxx, maxy;
  4465.                   int old_mode;
  4466.  
  4467.                   old_mode = fg_getmode();
  4468.  
  4469. 218  Fastgraph User's Guide
  4470.  
  4471.                   fg_setmode(fg_automode());
  4472.                   if (fg_mouseini() < 0) {
  4473.                      fg_setmode(old_mode);
  4474.                      fg_reset();
  4475.                      exit(1);
  4476.                      }
  4477.  
  4478.                   maxx = fg_getmaxx();
  4479.                   maxy = fg_getmaxy();
  4480.                   fg_setcolor(15);
  4481.                   fg_rect(0,maxx,0,maxy);
  4482.  
  4483.                   fg_mousevis(1);
  4484.                   fg_mouselim(maxx/4,3*maxx/4,maxy/4,3*maxy/4);
  4485.                   fg_waitkey();
  4486.  
  4487.                   fg_mousemov(0,0);
  4488.                   fg_waitfor(36);
  4489.                   fg_mousemov(maxx,0);
  4490.                   fg_waitfor(36);
  4491.                   fg_mousemov(maxx,maxy);
  4492.                   fg_waitfor(36);
  4493.                   fg_mousemov(0,maxy);
  4494.                   fg_waitfor(36);
  4495.                   fg_mousemov(maxx/2,maxy/2);
  4496.                   fg_mousespd(16,32);
  4497.                   fg_waitkey();
  4498.  
  4499.                   fg_setmode(old_mode);
  4500.                   fg_reset();
  4501.                }
  4502.  
  4503.  
  4504.  
  4505. Reporting the Mouse Status
  4506.  
  4507.      It is obviously important to be able to track the mouse position and
  4508. button status.  The Fastgraph routines fg_mousepos and fg_mousebut enable you
  4509. to do this.
  4510.  
  4511.      The fg_mousepos routine returns information about the current mouse
  4512. cursor position and button status.  It requires three integer arguments, all
  4513. passed by reference.  The first two arguments respectively receive the
  4514. horizontal and vertical coordinates of the mouse cursor.  These values are
  4515. expressed in screen space units for graphics modes and character cells for
  4516. text modes.  The third argument receives a three-bit mask containing the
  4517. button status as indicated below.
  4518.  
  4519.                  bit
  4520.                number  meaning
  4521.  
  4522.                   0    1 if left button pressed, 0 if not
  4523.                   1    1 if right button pressed, 0 if not
  4524.                   2    1 if middle button pressed, 0 if not
  4525.  
  4526.                                         Chapter 12:  Input Device Support  219
  4527.  
  4528.  
  4529. For example, if both the left and right buttons are pressed, the button
  4530. status will be set to 3.  If the mouse only has two buttons, bit 2 will
  4531. always be zero.
  4532.  
  4533.      Another routine, fg_mousebut, is available for returning the number of
  4534. button press or release counts that have occurred since the last check, or
  4535. since calling fg_mouseini.  Each mouse button maintains its own separate
  4536. counters, so fg_mousebut returns this information for a specific button.
  4537. Additionally, fg_mousebut returns the horizontal and vertical position of the
  4538. mouse cursor at the time the specified button was last pressed or released.
  4539.  
  4540.      The fg_mousebut routine takes four integer arguments, of which the last
  4541. three are passed by reference.  The first argument specifies the button of
  4542. interest (1 means the left button, 2 is the right button, and 3 is the middle
  4543. button).  If this value is positive, button press counts will be reported.
  4544. If it is negative, release counts will be reported.  The second, third, and
  4545. fourth arguments respectively receive the press or release count, the
  4546. horizontal mouse cursor position at the time of the last press or release,
  4547. and the vertical position at that same time.  If the press or release count
  4548. is zero, the mouse cursor position is returned as (0,0).  The coordinate
  4549. positions are expressed in screen space units for graphics modes and
  4550. character cells for text modes.
  4551.  
  4552.      Example 12-7 runs in any graphics video mode and illustrates the use of
  4553. the fg_mousepos and fg_mousebut routines.  The program first establishes the
  4554. video mode and then initializes the mouse (the program exits if the
  4555. initialization fails).  It next fills the entire screen with a white
  4556. rectangle and then calls fg_mousevis to make the mouse cursor visible.
  4557.  
  4558.      The main part of example 12-7 is a while loop that polls the mouse at
  4559. three-second intervals (the call fg_waitfor(54) delays the program for three
  4560. seconds).  Within the loop, the program first uses fg_mousebut to get the
  4561. number of times the left mouse button was pressed in the last three seconds.
  4562. Following this, the fg_mousepos routine gets the current mouse position.  The
  4563. program then displays this information in the upper left corner of the
  4564. screen; note how fg_mousevis is used to make the cursor invisible during
  4565. graphics operations.  The program continues until you press the right mouse
  4566. button, checked by the call to fg_mousebut at the end of the loop.
  4567.  
  4568.                                 Example 12-7.
  4569.  
  4570.           #include <fastgraf.h>
  4571.           #include <stdio.h>
  4572.           #include <stdlib.h>
  4573.           void main(void);
  4574.  
  4575.           void main()
  4576.           {
  4577.              int old_mode;
  4578.              int buttons, count;
  4579.              int x, y;
  4580.              char string[25];
  4581.  
  4582.              old_mode = fg_getmode();
  4583.              fg_setmode(fg_automode());
  4584.  
  4585. 220  Fastgraph User's Guide
  4586.  
  4587.              if (fg_mouseini() < 0) {
  4588.                 fg_setmode(old_mode);
  4589.                 fg_reset();
  4590.                 exit(1);
  4591.                 }
  4592.  
  4593.              fg_setcolor(15);
  4594.              fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  4595.              fg_mousevis(1);
  4596.  
  4597.              do {
  4598.                 fg_waitfor(54);
  4599.                 fg_mousebut(1,&count,&x,&y);
  4600.                 fg_mousepos(&x,&y,&buttons);
  4601.                 sprintf(string,"X=%3d  Y=%3d  count=%4d",x,y,count);
  4602.                 fg_mousevis(0);
  4603.                 fg_setcolor(15);
  4604.                 fg_rect(0,fg_xconvert(25),0,fg_yconvert(1));
  4605.                 fg_setcolor(0);
  4606.                 fg_locate(0,0);
  4607.                 fg_text(string,24);
  4608.                 fg_mousevis(1);
  4609.                 fg_mousebut(2,&count,&x,&y);
  4610.                 }
  4611.              while (count == 0);
  4612.  
  4613.              fg_setmode(old_mode);
  4614.              fg_reset();
  4615.           }
  4616.  
  4617.  
  4618.  
  4619. Defining the Mouse Cursor
  4620.  
  4621.      By default, the mouse cursor is a small white arrow in graphics modes
  4622. and a one-character rectangle in text modes.  In graphics modes, you can
  4623. change the mouse cursor to any 16 by 16 pixel image with the Fastgraph
  4624. routine fg_mouseptr (in the CGA four-color graphics modes, the cursor size is
  4625. 8 by 16 pixels).  You cannot change the mouse cursor shape in text modes, but
  4626. you can use the Fastgraph routine fg_mousecur to define how it interacts with
  4627. existing characters on the screen.
  4628.  
  4629. Text Modes
  4630.  
  4631.      To change the mouse cursor in text modes, you must first define two 16-
  4632. bit quantities called the screen mask and cursor mask.  The following figure
  4633. defines the format of each mask.
  4634.  
  4635.                        bits      meaning
  4636.  
  4637.                        0 to 7    ASCII character value
  4638.                        8 to 11   foreground color
  4639.                        12 to 14  background color
  4640.                        15        blink
  4641.  
  4642.                                         Chapter 12:  Input Device Support  221
  4643.  
  4644.  
  4645. Notice how this structure parallels the character and attribute bytes
  4646. associated with each character cell.  The default screen mask is 77FF hex,
  4647. and the default cursor mask is 7700 hex.
  4648.  
  4649.      When you position the mouse over a specific character cell, the mouse
  4650. driver uses the current screen and cursor masks to determine the mouse
  4651. cursor's appearance.  First, the mouse driver logically ANDs the screen mask
  4652. with the existing contents of that character cell.  It then XORs that result
  4653. with the cursor mask to display the mouse cursor.
  4654.  
  4655.      For example, consider how the mouse cursor is produced in the 80-column
  4656. color text mode (mode 3).  Suppose a specific character cell contains the
  4657. ASCII character 0 (48 decimal, 30 hex) and an attribute byte that specifies a
  4658. white (color 15) foreground on a blue background (color 1) and does not blink
  4659. (blink bit 0).  The binary structure of the character and its attribute are:
  4660.  
  4661.                             attribute    character
  4662.  
  4663.                             0 001 1111   00110000
  4664.  
  4665. Now let's see what happens when we apply the screen and cursor masks to the
  4666. character and its attribute.
  4667.  
  4668.             attribute/character   0001 1111 0011 0000   (1F30 hex)
  4669.             default screen mask   0111 0111 1111 1111   (77FF hex)
  4670.                                   -------------------
  4671.             result of AND         0001 0111 0011 0000   (1730 hex)
  4672.             default cursor mask   0111 0111 0000 0000   (7700 hex)
  4673.                                   -------------------
  4674.             result of XOR         0110 0000 0011 0000   (6030 hex)
  4675.  
  4676. The resulting character (30 hex) is the original character, but the new
  4677. attribute (60 hex) represents a black foreground with a brown background and
  4678. does not blink.  As long as the mouse cursor remains positioned on this
  4679. character cell, it would appear black on brown.
  4680.  
  4681.      When we use the default screen and cursor masks, the mouse cursor will
  4682. always display the original character and it will not blink.  The cursor
  4683. foreground color will be 15-F, where F is the displayed character's
  4684. foreground color.  Similarly, the cursor background color will be 7-B, where
  4685. B is the displayed character's background color.  The default masks will
  4686. virtually always produce a satisfactory mouse cursor.
  4687.  
  4688.      It is possible, however, to change the appearance of the mouse cursor in
  4689. text modes by using your own screen and cursor masks.  The Fastgraph routine
  4690. fg_mousecur does just that.  It expects two arguments, the first being the
  4691. cursor mask and the second the screen mask.  Example 12-8 demonstrates the
  4692. use of fg_mousecur.  The program displays some text and uses the default
  4693. mouse cursor.  After waiting for a keystroke, the program calls fg_mousecur
  4694. to define a new mouse cursor.  The new cursor is similar to the default
  4695. cursor, but it displays the foreground colors in the opposite intensity as
  4696. 222  Fastgraph User's Guide
  4697.  
  4698. the default cursor.  The program then waits for another keystroke before
  4699. returning to DOS.
  4700.  
  4701.                                 Example 12-8.
  4702.  
  4703.                   #include <fastgraf.h>
  4704.                   #include <stdio.h>
  4705.                   #include <stdlib.h>
  4706.                   void main(void);
  4707.  
  4708.                   void main()
  4709.                   {
  4710.                      int old_mode;
  4711.                      int row;
  4712.  
  4713.                      old_mode = fg_getmode();
  4714.                      fg_setmode(3);
  4715.  
  4716.                      if (fg_mouseini() < 0) {
  4717.                         fg_setmode(old_mode);
  4718.                         fg_reset();
  4719.                         exit(1);
  4720.                         }
  4721.  
  4722.                      fg_setattr(7,0,0);
  4723.                      fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  4724.  
  4725.                      fg_setattr(12,7,0);
  4726.                      for (row = 0; row < 25; row++) {
  4727.                         fg_locate(row,34);
  4728.                         fg_text("example 12-8",12);
  4729.                         }
  4730.  
  4731.                      fg_mousevis(1);
  4732.                      fg_waitkey();
  4733.                      fg_mousecur(0x7FFF,0x7F00);
  4734.                      fg_waitkey();
  4735.  
  4736.                      fg_setmode(old_mode);
  4737.                      fg_reset();
  4738.                   }
  4739.  
  4740.  
  4741. Graphics Modes
  4742.  
  4743.      Defining the mouse cursor in graphics video modes also requires creating
  4744. a screen mask and cursor mask, but as one might expect, the structure of
  4745. these masks is vastly different from for text modes.  In fact, it closely
  4746. resembles the mode-independent bit map format used by the fg_drawmap routine.
  4747. Although their structure differs, the way the mouse driver uses the masks is
  4748. the same as in the text modes.  That is, the driver displays the mouse cursor
  4749. by first logically ANDing video memory with the screen mask, and then XORing
  4750. that result with the cursor mask.
  4751.  
  4752.      Let's begin by looking at the masks for the default mouse cursor in
  4753. graphics modes.  The size of each mask (and hence the mouse cursor) is 16
  4754. pixels wide and 16 pixels high.  As mentioned earlier, the default cursor is
  4755.                                         Chapter 12:  Input Device Support  223
  4756.  
  4757. a small white arrow with a black outline around it.  Here are its screen and
  4758. cursor masks expressed as binary values.
  4759.  
  4760.             screen                  cursor                  cursor
  4761.              mask                    mask                 appearance
  4762.  
  4763.        1001111111111111        0000000000000000         **
  4764.        1000111111111111        0010000000000000         *x*
  4765.        1000011111111111        0011000000000000         *xx*
  4766.        1000001111111111        0011100000000000         *xxx*
  4767.        1000000111111111        0011110000000000         *xxxx*
  4768.        1000000011111111        0011111000000000         *xxxxx*
  4769.        1000000001111111        0011111100000000         *xxxxxx*
  4770.        1000000000111111        0011111110000000         *xxxxxxx*
  4771.        1000000000011111        0011111111000000         *xxxxxxxx*
  4772.        1000000000001111        0011111000000000         *xxxxx*****
  4773.        1000000011111111        0011011000000000         *xx*xx*
  4774.        1000100001111111        0010001100000000         *x* *xx*
  4775.        1001100001111111        0000001100000000         **  *xx*
  4776.        1111110000111111        0000000110000000              *xx*
  4777.        1111110000111111        0000000110000000              *xx*
  4778.        1111111000111111        0000000000000000               ***
  4779.  
  4780.      The mouse driver first ANDs the screen mask with video memory at the
  4781. mouse cursor position.  This means the screen mask 1 bits leave video memory
  4782. intact, while the 0 bits change the corresponding pixels to black.  Next, the
  4783. mouse driver XORs the result with the cursor mask.  This time the cursor mask
  4784. 0 bits leave video memory unchanged, while the 1 bits change the
  4785. corresponding pixels to white.  This produces a mouse cursor as shown above
  4786. on the right, where a dot ( ) represents an unchanged pixel, an asterisk (*)
  4787. a black pixel, and an x a white pixel.  The following table summarizes the
  4788. cursor appearance for all possible combinations of mask bits.
  4789.  
  4790.           screen mask bit   cursor mask bit   resulting cursor pixel
  4791.  
  4792.                  0                 0          black
  4793.                  0                 1          white
  4794.                  1                 0          unchanged
  4795.                  1                 1          inverted
  4796.  
  4797.      The color of an "inverted" pixel is n-k, where n is the maximum color
  4798. number in the current video mode, and k is the color of the pixel being
  4799. replaced.  Also, "black" and "white" pixels are not necessarily these colors
  4800. in 16-color and 256-color modes.  More correctly, "black" pixels are
  4801. displayed in the color assigned to palette 0, and "white" pixels are the
  4802. displayed in the color assigned to palette 15.  If you're using the CGA color
  4803. modes, "black" pixels are displayed in the background color, and "white"
  4804. pixels appear in color 3 (whose actual color is determined by the selected
  4805. CGA palette).
  4806.  
  4807.      With an understanding of the way the default mouse cursor works in
  4808. graphics modes, we're now ready to define our own mouse cursor.  Shown below
  4809. are the screen mask, cursor mask, and resulting appearance for a solid plus-
  4810. shaped cursor.  The hexadecimal equivalents of the binary mask values are
  4811. also given.
  4812. 224  Fastgraph User's Guide
  4813.  
  4814.    ----- screen mask ----      ----- cursor mask ----
  4815.                                                                 cursor
  4816.         binary       hex            binary       hex          appearance
  4817.  
  4818.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  4819.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  4820.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  4821.    0000000000000111  0007      0000111110000000  0F80      ****xxxxx****...
  4822.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  4823.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  4824.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  4825.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  4826.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  4827.    0000000000000111  0007      0000111110000000  0F80      ****xxxxx****...
  4828.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  4829.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  4830.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  4831.    1111111111111111  FFFF      0000000000000000  0000      ................
  4832.    1111111111111111  FFFF      0000000000000000  0000      ................
  4833.    1111111111111111  FFFF      0000000000000000  0000      ................
  4834.  
  4835. If we wanted to make the mouse cursor hollow rather than solid, the masks and
  4836. resulting cursor appearance would look like this.
  4837.  
  4838.    ----- screen mask ----      ----- cursor mask ----
  4839.                                                                 cursor
  4840.         binary       hex            binary       hex          appearance
  4841.  
  4842.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  4843.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  4844.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  4845.    0000111110000111  0F87      0000000000000000  0000      ****.....****...
  4846.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  4847.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  4848.    0111111111110111  7FF7      0000001000000000  0200      *.....x.....*...
  4849.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  4850.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  4851.    0000111110000111  0F87      0000000000000000  0000      ****.....****...
  4852.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  4853.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  4854.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  4855.    1111111111111111  FFFF      0000000000000000  0000      ................
  4856.    1111111111111111  FFFF      0000000000000000  0000      ................
  4857.    1111111111111111  FFFF      0000000000000000  0000      ................
  4858.  
  4859. Note that the center bit defined in the cursor mask causes the corresponding
  4860. pixel in video memory to be inverted.
  4861.  
  4862.      There is one more item needed to define a graphics mode mouse cursor
  4863. completely.  That item is the hot spot, or the actual screen position used or
  4864. reported by the mouse driver.  For the plus-shaped cursors just constructed,
  4865. it would be sensible to define the hot spot in the center of the plus.  The
  4866. hot spot is specified relative to the upper left corner of the cursor, so its
  4867. position within the cursor would be (6,6) -- that is, six pixels to the right
  4868. and six pixels below the upper left corner.  You can specify the hot spot
  4869. offsets using negative values or values above 15 to position it outside the
  4870. mouse cursor matrix if desired.
  4871.                                         Chapter 12:  Input Device Support  225
  4872.  
  4873.  
  4874.      The Fastgraph routine fg_mouseptr defines a mouse cursor in graphics
  4875. modes.  The first of its three arguments is a 32-element integer array,
  4876. passed by reference.  The array's first 16 elements contain the screen mask,
  4877. and its second 16 elements contain the cursor mask.  The remaining two
  4878. arguments respectively specify the horizontal and vertical offsets for the
  4879. hot spot.  The fg_mouseptr routine has no effect in a text video mode.
  4880.  
  4881.      Example 12-9 is similar to example 12-8.  It shows how to define a
  4882. graphics mode mouse cursor using fg_mouseptr.  The values stored in the solid
  4883. and hollow arrays define the screen and cursor masks for the solid and hollow
  4884. plus-shaped mouse cursors discussed earlier.  After making the mouse cursor
  4885. visible, the program uses the default mouse cursor until a key is pressed.
  4886. Following this, it changes to the solid cursor.  After another keystroke, the
  4887. program changes to the hollow cursor.  When you run example 12-9, compare the
  4888. differences among the three mouse cursors.
  4889.  
  4890.                                 Example 12-9.
  4891.  
  4892.   #include <fastgraf.h>
  4893.   #include <stdio.h>
  4894.   #include <stdlib.h>
  4895.   void main(void);
  4896.  
  4897.   int solid[]  = {0xE03F,0xE03F,0xE03F,0x0007,0x0007,0x0007,0x0007,0x0007,
  4898.                   0x0007,0x0007,0xE03F,0xE03F,0xE03F,0xFFFF,0xFFFF,0xFFFF,
  4899.                   0x0000,0x0F80,0x0F80,0x0F80,0x7FF0,0x7FF0,0x7FF0,0x7FF0,
  4900.                   0x7FF0,0x0F80,0x0F80,0x0F80,0x0000,0x0000,0x0000,0x0000};
  4901.  
  4902.   int hollow[] = {0xE03F,0xEFBF,0xEFBF,0x0F87,0x7FF7,0x7FF7,0x7FF7,0x7FF7,
  4903.                   0x7FF7,0x0F87,0xEFBF,0xEFBF,0xE03F,0xFFFF,0xFFFF,0xFFFF,
  4904.                   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0200,0x0000,
  4905.                   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
  4906.  
  4907.   void main()
  4908.   {
  4909.      int old_mode;
  4910.      int column, row, last_row;
  4911.  
  4912.      old_mode = fg_getmode();
  4913.      fg_setmode(fg_automode());
  4914.  
  4915.      if (fg_mouseini() < 0) {
  4916.         fg_setmode(old_mode);
  4917.         fg_reset();
  4918.         exit(1);
  4919.         }
  4920.      fg_setcolor(15);
  4921.      fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  4922.  
  4923.      fg_setcolor(12);
  4924.      column = fg_xalpha(fg_getmaxx()/2) - 6;
  4925.      last_row = fg_yalpha(fg_getmaxy()) + 1;
  4926.      for (row = 0; row < last_row; row++) {
  4927.         fg_locate(row,column);
  4928.         fg_text("example 12-9",12);
  4929.  
  4930. 226  Fastgraph User's Guide
  4931.  
  4932.         }
  4933.  
  4934.      fg_mousevis(1);
  4935.      fg_waitkey();
  4936.      fg_mouseptr(solid,6,6);
  4937.      fg_waitkey();
  4938.      fg_mouseptr(hollow,6,6);
  4939.      fg_waitkey();
  4940.  
  4941.      fg_setmode(old_mode);
  4942.      fg_reset();
  4943.   }
  4944.  
  4945.  
  4946. CGA Considerations
  4947.  
  4948.      The mouse driver treats the screen and cursor masks differently in the
  4949. CGA four-color graphics modes (modes 4 and 5) than in the other graphics
  4950. modes.  In the CGA modes, each pair of mask bits corresponds to one pixel.
  4951. This means the masks more closely resemble the mode-specific format used by
  4952. fg_drwimage instead of the mode-independent format of fg_drawmap.
  4953.  
  4954.      Fastgraph uses a different default mouse cursor for modes 4 and 5.  Its
  4955. screen and cursor masks, as well as the resulting cursor appearance, are
  4956. shown in the following diagram.
  4957.  
  4958.                 screen                  cursor              cursor
  4959.                 mask                    mask             appearance
  4960.  
  4961.            0000111111111111        0000000000000000        **
  4962.            0000001111111111        0011000000000000        ***
  4963.            0000000011111111        0011110000000000        ****
  4964.            0000000000111111        0011111100000000        *****
  4965.            0000000000001111        0011111111000000        ******
  4966.            0000000000000011        0011111111110000        *******
  4967.            0000000000000011        0011111100000000        *******
  4968.            0000000000111111        0011111110000000        *****
  4969.            0000000000001111        0011000011000000        ******
  4970.            0000110000001111        0000000011000000        ** ***
  4971.            1111111100000011        0000000000110000            ***
  4972.            1111111100000011        0010000000110000            ***
  4973.            1111111111000011        0000000000000000             **
  4974.            1111111111111111        0000000000000000
  4975.            1111111111111111        0000000000000000
  4976.            1111111111111111        0000000000000000
  4977.  
  4978. As you can see, the resulting mouse cursor is eight pixels wide instead of
  4979. 16.
  4980.  
  4981.      Another important point concerning mouse cursors in modes 4 and 5 is the
  4982. chance of pixel bleeding, or the changing of colors within the mouse cursor
  4983. as it moves horizontally.  Bleeding will occur if you use the bit pairs 01 or
  4984. 10 in either mask to represent a pixel.  In the default masks for modes 4 and
  4985. 5, note that only the binary values 00 and 11 appear as bit pairs.  Keep this
  4986. in mind if you create your own masks in these video modes.
  4987.                                         Chapter 12:  Input Device Support  227
  4988.  
  4989.  
  4990. Joystick Support
  4991.  
  4992.      The third type of input device supported by Fastgraph is the joystick.
  4993. Although joysticks are not as popular as mice, they are often preferable when
  4994. a user's reactions are critical, such as in an arcade-style game.  Fastgraph
  4995. includes routines for initializing a joystick, reading a joystick's position
  4996. or button status, and making a joystick behave analogously to the keyboard.
  4997. These routines are independent of the rest of Fastgraph and thus do not
  4998. require that you first call the fg_setmode routine.
  4999.  
  5000.      Joysticks are connected to a system through a game port.  The PCjr and
  5001. Tandy 1000 systems come equipped with two game ports, and hence support two
  5002. joysticks.  On other systems in the IBM family, you can install a game port
  5003. card that contains either one or two game ports.  If the card only has one
  5004. game port, you can use a splitter cable to fork two joysticks into the port.
  5005.  
  5006.  
  5007. Initializing Joysticks
  5008.  
  5009.      Before you can use any of Fastgraph's joystick support routines with a
  5010. specific joystick, you must initialize that joystick.  The fg_initjoy routine
  5011. performs this task.  This routine requires a single integer argument that
  5012. specifies which joystick to initialize, either 1 or 2.  If successful,
  5013. fg_initjoy returns 0 as the function value.  If the machine has no game port,
  5014. or if the requested joystick is not connected to the game port, fg_initjoy
  5015. returns -1.  When you use fg_initjoy, the joystick being initialized must be
  5016. centered (that is, the stick itself must not be tilted in either direction).
  5017.  
  5018.      Example 12-10 uses the fg_initjoy routine to try to initialize both
  5019. joysticks.  For each joystick, the program prints a message stating whether
  5020. or not the initialization was successful.
  5021.  
  5022.                                 Example 12-10.
  5023.  
  5024.                  #include <fastgraf.h>
  5025.                  #include <stdio.h>
  5026.                  void main(void);
  5027.  
  5028.                  void main()
  5029.                  {
  5030.                     if (fg_initjoy(1) < 0)
  5031.                        printf("Joystick 1 not available.\n");
  5032.                     else
  5033.                        printf("Joystick 1 found.\n");
  5034.  
  5035.                     if (fg_initjoy(2) < 0)
  5036.                        printf("Joystick 2 not available.\n");
  5037.                     else
  5038.                        printf("Joystick 2 found.\n");
  5039.                  }
  5040.  
  5041. 228  Fastgraph User's Guide
  5042.  
  5043. Reporting Joystick Status
  5044.  
  5045.      Each joystick can report three items:  its horizontal position, its
  5046. vertical position, and the button status.  Fastgraph includes routines for
  5047. obtaining each of these quantities.
  5048.  
  5049.      The fg_getxjoy and fg_getyjoy routines respectively return the
  5050. horizontal and vertical position of the indicated joystick.  Both routines
  5051. require a single integer argument, whose value is either 1 or 2, to identify
  5052. the joystick.  The requested position is returned as the function value.
  5053. Horizontal coordinates increase as the joystick moves to the right, while
  5054. vertical coordinates increase as the joystick moves downward.  If fg_initjoy
  5055. did not initialize the specified joystick, or if your program hasn't yet
  5056. called fg_initjoy, both fg_getxjoy and fg_getyjoy will return the value -1.
  5057.  
  5058.      Joystick characteristics vary more than those of any other input device.
  5059. The values returned by fg_getxjoy and fg_getyjoy depend on the system's
  5060. processor speed and the brand of joystick used.  It often suffices to know
  5061. the joystick position relative to its previous position, in which case the
  5062. actual coordinate values do not matter.  However, if you must rely on
  5063. specific coordinate values, your program must perform some type of manual
  5064. joystick calibration and then scale the coordinates reported by fg_getxjoy
  5065. and fg_getyjoy as needed.
  5066.  
  5067.      The other piece of information joysticks provide is the button status.
  5068. Most joysticks have two buttons, called the top and bottom buttons.  Others
  5069. have three buttons, but one of them duplicates the functionality of another
  5070. (for example, a joystick might have one bottom button on its left side and
  5071. another on its right side).  The Fastgraph routine fg_button returns the
  5072. joystick button status as its function value.  Like fg_getxjoy and
  5073. fg_getyjoy, the fg_button routine requires a single argument that specifies
  5074. the joystick number.  The meaning of the returned value is shown below.
  5075.  
  5076.                    value  meaning
  5077.  
  5078.                      0    neither button pressed
  5079.                      1    top button pressed
  5080.                      2    bottom button pressed
  5081.                      3    top and bottom buttons pressed
  5082.  
  5083.      You don't need to call fg_initjoy before using fg_button.  If the
  5084. specified joystick is not present, the fg_button routine will return a value
  5085. of 0.
  5086.  
  5087.      Example 12-11 uses fg_getxjoy, fg_getyjoy, and fg_button to poll both
  5088. joysticks at half-second intervals.  It then displays the joystick number (1
  5089. or 2), horizontal position, vertical position, and button status for each
  5090. joystick.  As the program runs, you can move the joysticks and watch how the
  5091. movements affect the displayed coordinate values.  The program continues
  5092. doing this until you press Ctrl/C or Ctrl/Break to stop it.
  5093.                                         Chapter 12:  Input Device Support  229
  5094.  
  5095.                                 Example 12-11.
  5096.  
  5097.                   #include <fastgraf.h>
  5098.                   #include <stdio.h>
  5099.  
  5100.                   void main(void);
  5101.  
  5102.                   void main()
  5103.                   {
  5104.                      int b, x, y;
  5105.  
  5106.                      fg_initjoy(1);
  5107.                      fg_initjoy(2);
  5108.  
  5109.                      while (1) {
  5110.                         x = fg_getxjoy(1);
  5111.                         y = fg_getyjoy(1);
  5112.                         b = fg_button(1);
  5113.                         printf("1:  %3d %3d %1d\n",x,y,b);
  5114.                         x = fg_getxjoy(2);
  5115.                         y = fg_getyjoy(2);
  5116.                         b = fg_button(2);
  5117.                         printf("2:  %3d %3d %1d\n\n",x,y,b);
  5118.                         fg_waitfor(9);
  5119.                         }
  5120.                   }
  5121.  
  5122.  
  5123.      There are two ways of effectively monitoring joystick button status.
  5124. One is to call fg_button at many places in your program and then take the
  5125. necessary action depending on the button status.  However, the preferable
  5126. method is to extend the BIOS time-of-day interrupt to check the button status
  5127. at each clock tick (there are 18.2 clock ticks per second), set a flag if a
  5128. button is pressed, and then check the flag as needed in your program.
  5129. Information on changing the BIOS time-of-day interrupt appears in Appendix C
  5130. of this document.
  5131.  
  5132.  
  5133. Keyboard Emulation
  5134.  
  5135.      Although we can use the fg_getxjoy and fg_getyjoy routines to monitor
  5136. relative joystick movements, it is usually easier to do this with another
  5137. Fastgraph routine, fg_intjoy.  This routine is similar to the fg_intkey
  5138. routine in that it returns two values that are equivalent to the standard or
  5139. extended keyboard codes for analogous keystrokes.
  5140.  
  5141.      The fg_intjoy routine needs three arguments.  The first argument
  5142. specifies the joystick number, either 1 or 2.  The second and third
  5143. arguments, both one-byte quantities passed by reference, receive the standard
  5144. and extended keyboard codes analogous to the joystick movement and button
  5145. status.  The second argument receives a value of 13 (the standard keyboard
  5146. code for the Enter key) if any joystick button is pressed; it receives a
  5147. value of 0 if not.  The third argument receives a value corresponding to the
  5148. extended keyboard code for one of the directional keys on the numeric keypad,
  5149. as summarized in the following table.
  5150. 230  Fastgraph User's Guide
  5151.  
  5152.            joystick position  corresponding key  extended key code
  5153.  
  5154.            up and left        Home               71
  5155.            up                 up arrow           72
  5156.            up and right       PgUp               73
  5157.            left               left arrow         75
  5158.            centered           (no action)         0
  5159.            right              right arrow        77
  5160.            down and left      End                79
  5161.            down               down arrow         80
  5162.            down and right     PgDn               81
  5163.  
  5164. The fg_intjoy routine will set both key code arguments to zero if the
  5165. specified joystick has not yet been initialized.
  5166.  
  5167.      Example 12-12 is similar to example 12-10, but it uses fg_intjoy in
  5168. place of fg_getxjoy and fg_getyjoy to report relative joystick position.
  5169. This program does not report the joystick button status as example 12-10
  5170. does, but you could readily add this feature to it.
  5171.  
  5172.                                 Example 12-12.
  5173.  
  5174.                    #include <fastgraf.h>
  5175.                    #include <stdio.h>
  5176.                    void main(void);
  5177.  
  5178.                    void main()
  5179.                    {
  5180.                       char key, aux;
  5181.  
  5182.                       fg_initjoy(1);
  5183.                       fg_initjoy(2);
  5184.  
  5185.                       while (1) {
  5186.                          fg_intjoy(1,&key,&aux);
  5187.                          printf("1: %2d %2d\n",key,aux);
  5188.                          fg_intjoy(2,&key,&aux);
  5189.                          printf("2: %2d %2d\n\n",key,aux);
  5190.                          fg_waitfor(9);
  5191.                          }
  5192.                    }
  5193.  
  5194.  
  5195.  
  5196. Special Joystick Considerations
  5197.  
  5198.      If you develop a program that supports only one joystick, you should use
  5199. joystick 1.  The reasons for this are twofold.  First, it will make your
  5200. program consistent with most other products that support joysticks.  Second,
  5201. and perhaps more importantly, many Tandy 1000 series machines cannot
  5202. determine if joystick 2 is present when neither joystick is connected.  This
  5203. means if you use joystick 2 instead of joystick 1 in a single joystick
  5204. program, you won't be able to tell if a joystick is available when running on
  5205. a Tandy 1000.
  5206.                                         Chapter 12:  Input Device Support  231
  5207.  
  5208. Summary of Input Routines
  5209.  
  5210.      This section summarizes the functional descriptions of the Fastgraph
  5211. routines presented in this chapter.  More detailed information about these
  5212. routines, including their arguments and return values, may be found in the
  5213. Fastgraph Reference Manual.
  5214.  
  5215.      FG_BUTTON returns information about the state of either joystick's
  5216. buttons.
  5217.  
  5218.      FG_CAPSLOCK determines the state of the CapsLock key.
  5219.  
  5220.      FG_GETKEY waits for a keystroke (or reads the next entry from the BIOS
  5221. keyboard buffer). It returns the keystroke's standard or extended keyboard
  5222. code.
  5223.  
  5224.      FG_GETXJOY and FG_GETYJOY return the horizontal and vertical coordinate
  5225. position of the specified joystick.  The actual coordinates depend on the
  5226. processor speed and brand of joystick used.
  5227.  
  5228.      FG_INITJOY initializes joystick 1 or 2 and must be called before using
  5229. fg_getxjoy, fg_getyjoy, or fg_intjoy.  It returns a status code indicating
  5230. whether or not the initialization was successful.
  5231.  
  5232.      FG_INTJOY returns the standard and extended keyboard codes analogous to
  5233. the current position and button status of the specified joystick.
  5234.  
  5235.      FG_INTKEY reads the next entry from the BIOS keyboard buffer and returns
  5236. the keystroke's standard or extended keyboard code.  It is similar to
  5237. fg_getkey, but it does not wait for a keystroke if the keyboard buffer is
  5238. empty.
  5239.  
  5240.      FG_MOUSEBUT returns information about mouse button press or release
  5241. counts, as well as the mouse cursor position at the time of the last button
  5242. press or release.
  5243.  
  5244.      FG_MOUSECUR defines the appearance of the mouse cursor in text video
  5245. modes.
  5246.  
  5247.      FG_MOUSEINI initializes the mouse and must be called before any of
  5248. Fastgraph's other mouse support routines.  It returns an error status if the
  5249. mouse driver has not been loaded, or if the mouse is not connected.
  5250.  
  5251.      FG_MOUSELIM defines the rectangular area in which the mouse cursor may
  5252. move.
  5253.  
  5254.      FG_MOUSEMOV moves the mouse cursor to the specified character cell (in
  5255. text modes) or screen space position (in graphics modes).
  5256.  
  5257.      FG_MOUSEPOS returns the current mouse position and button status.
  5258.  
  5259.      FG_MOUSEPTR defines the shape and appearance of the mouse cursor in
  5260. graphics video modes.
  5261.  
  5262.      FG_MOUSESPD defines the number of mickey units per eight pixels of
  5263. cursor movement.  This effectively controls the speed at which the mouse
  5264. cursor moves relative to the movement of the mouse itself.
  5265. 232  Fastgraph User's Guide
  5266.  
  5267.  
  5268.      FG_MOUSEVIS makes the mouse cursor visible or invisible.
  5269.  
  5270.      FG_NUMLOCK determines the state of the NumLock key.
  5271.  
  5272.      FG_SCRLOCK determines the state of the ScrollLock key (which is not
  5273. present on some keyboards).
  5274.  
  5275.      FG_SETCAPS controls the state of the CapsLock key.
  5276.  
  5277.      FG_SETNUM controls the state of the NumLock key.
  5278.  
  5279.      FG_WAITKEY flushes the BIOS keyboard buffer (that is, removes any type-
  5280. ahead characters) and then waits for another keystroke.
  5281.  
  5282.  
  5283. Chapter 13
  5284.  
  5285. Sound Effects
  5286. 234  Fastgraph User's Guide
  5287.  
  5288. Overview
  5289.  
  5290.      In the realm of the IBM PC and PS/2 family of systems, a sound is
  5291. defined by its frequency, duration, and volume.  The frequency of a sound is
  5292. measured in units called Hertz.  While the PC and PS/2 can produce sounds
  5293. ranging from 18 to more than one million Hertz, the average human can hear
  5294. sounds between 20 and about 20,000 Hertz.  The length of a sound, called its
  5295. duration, is expressed in clock ticks; there are either 18.2 of 72.8 clock
  5296. ticks per second, depending on the method used to produce the sound.
  5297. Finally, the volume determines the loudness of the sound.  As we'll see in
  5298. this chapter, we can control a sound's volume only on the PCjr and Tandy 1000
  5299. systems.
  5300.  
  5301.      Fastgraph contains several different methods for producing sound
  5302. effects.  These include single tones, a series of tones expressed
  5303. numerically, or a series of tones expressed as musical notes.  The sound
  5304. effects may be discrete, continuous, or performed at the same time as other
  5305. activity.  The sound-related routines are independent of the other parts of
  5306. Fastgraph and do not require any initialization routines be called.
  5307.  
  5308.  
  5309. Sound Sources
  5310.  
  5311.      All members of the PC and PS/2 families can produce sounds using the
  5312. 8253-5 programmable timer chip and the internal speaker.  This method is
  5313. limited to producing single sounds of given frequencies and durations,
  5314. although we can combine these sounds to create interesting audio effects or
  5315. play music.  When we use this technique, we have no control over the sound
  5316. volume.  In fact, sound volumes often vary slightly on different systems
  5317. because the physical properties of the speaker and its housing are not always
  5318. the same.
  5319.  
  5320.      The PCjr and Tandy 1000 systems have an additional, more powerful chip
  5321. for producing sounds.  This is the Texas Instruments SN76496A sound chip,
  5322. called the TI sound chip for short.  The TI sound chip has three independent
  5323. voice channels for producing pure tones, and a fourth channel for generating
  5324. periodic or white noise.  Each voice channel has a separate volume control
  5325. that allows us to control the loudness of the sound it emits.
  5326.  
  5327.  
  5328. Synchronous Sound
  5329.  
  5330.      A sound effect is said to be synchronous if it is produced while no
  5331. other activity is being performed.  In other words, a program makes a
  5332. synchronous sound by starting the sound, waiting for a specified duration,
  5333. and then stopping the sound.  The program must wait for the sound to complete
  5334. before doing anything else.  As long as the duration is relatively short, the
  5335. fact that the sound is synchronous has little or no effect on the program's
  5336. execution speed.  Fastgraph includes routines for producing synchronous sound
  5337. using either the 8253-5 programmable timer or the TI sound chip.
  5338.  
  5339.      The fg_sound routine uses the programmable timer to produce a sound of a
  5340. given frequency and duration.  The frequency, defined by the first argument,
  5341. is expressed in Hertz and must be an integer value between 18 and 32,767.
  5342. The second argument defines the duration and is expressed in clock ticks;
  5343. there are 18.2 clock ticks per second.  If the duration is zero or negative,
  5344. the sound will continue until it is stopped with the fg_quiet routine.
  5345.                                                Chapter 13:  Sound Effects  235
  5346.  
  5347.  
  5348.      Example 13-1 uses the fg_sound routine to create different sound
  5349. effects, pausing for one second between each.  It first produces three
  5350. distinct sounds of 20, 100, and 1,000 Hertz.  Each of these sounds lasts for
  5351. approximately 1/6 of a second (three clock ticks).  The program then makes a
  5352. warbling noise by quickly alternating sounds of similar frequencies.
  5353. Finally, the program creates a sliding tone of increasing frequencies between
  5354. 100 and 500 Hertz.  Each tone in this sequence lasts for two clock ticks, so
  5355. it takes about 4.5 seconds to play the entire sequence.  In all cases,
  5356. example 13-1 displays an identifying message just before each sound.
  5357.  
  5358.                                 Example 13-1.
  5359.  
  5360.               #include <fastgraf.h>
  5361.               #include <stdio.h>
  5362.               void main(void);
  5363.  
  5364.               void main()
  5365.               {
  5366.                  int freq;
  5367.  
  5368.                  printf("20 Hz tone...\n");
  5369.                  fg_sound(20,3);
  5370.                  fg_waitfor(18);
  5371.  
  5372.                  printf("100 Hz tone...\n");
  5373.                  fg_sound(100,3);
  5374.                  fg_waitfor(18);
  5375.  
  5376.                  printf("1000 Hz tone...\n");
  5377.                  fg_sound(1000,3);
  5378.                  fg_waitfor(18);
  5379.  
  5380.                  printf("warble...\n");
  5381.                  fg_sound(400,1);
  5382.                  fg_sound(410,1);
  5383.                  fg_sound(400,1);
  5384.                  fg_sound(410,1);
  5385.                  fg_waitfor(18);
  5386.  
  5387.                  printf("sliding tone from 100 to 500 Hz...\n");
  5388.                  for (freq = 100; freq <= 500; freq+=10)
  5389.                     fg_sound(freq,2);
  5390.               }
  5391.  
  5392.  
  5393.      The fg_voice routine is analogous to the fg_sound routine, but it uses
  5394. the TI sound chip rather than the programmable timer to create sound.  For
  5395. this reason, the fg_voice routine can only be used on the PCjr or Tandy 1000
  5396. systems.  The TI sound chip allows us to control the volume of a sound, and
  5397. it also offers four distinct voice channels.  Thus, fg_voice requires two
  5398. additional arguments besides frequency and duration to define the voice
  5399. channel and sound volume.
  5400.  
  5401.      The first argument to fg_voice defines the voice channel, as shown
  5402. below.
  5403. 236  Fastgraph User's Guide
  5404.  
  5405.                    value meaning
  5406.  
  5407.                      1   voice channel #1
  5408.                      2   voice channel #2
  5409.                      3   voice channel #3
  5410.                      4   voice channel #4, periodic noise
  5411.                      5   voice channel #4, white noise
  5412.  
  5413. If we use voice channels 1, 2, or 3, the second argument defines the sound
  5414. frequency in Hertz, between 18 and 32,767.  If we use voice channel 4,
  5415. however, the second argument instead is a value that represents a specific
  5416. frequency, as shown in this table.
  5417.  
  5418.                                value  frequency
  5419.  
  5420.                                  0    512 Hertz
  5421.                                  1   1024 Hertz
  5422.                                  2   2048 Hertz
  5423.  
  5424. The third argument defines the sound volume.  It must be between 0 and 15,
  5425. where 0 is silent and 15 is loudest.  The fourth argument defines the sound
  5426. duration in clock ticks.  As with the fg_sound routine, there are 18.2 clock
  5427. ticks per second, and if the duration is zero or negative, the sound will
  5428. continue until stopped with the fg_quiet routine.
  5429.  
  5430.      Example 13-2 uses the fg_voice routine to create different sound effects
  5431. using the TI sound chip.  As in example 13-1, there is a pause of one second
  5432. between each.  The program first calls the fg_testmode routine to be sure it
  5433. is running on a PCjr or Tandy 1000 system (video mode 9 is only available on
  5434. these systems).  If so, the program uses voice channel #4 to produce a 2,048
  5435. Hertz periodic noise, followed by white noise of the same frequency.  Both
  5436. sounds are emitted at the maximum volume level (15) and last for about 1/6 of
  5437. a second each (three clock ticks).  After these noises, example 13-2 produces
  5438. a 500 Hertz tone of increasing volume.  In all cases, the program displays an
  5439. identifying message just before each sound.
  5440.  
  5441.                                 Example 13-2.
  5442.  
  5443.              #include <fastgraf.h>
  5444.              #include <stdio.h>
  5445.              #include <stdlib.h>
  5446.              void main(void);
  5447.  
  5448.              void main()
  5449.              {
  5450.                 int volume;
  5451.  
  5452.                 if (fg_testmode(9,0) == 0) {
  5453.  
  5454.                                                Chapter 13:  Sound Effects  237
  5455.  
  5456.                    printf("This program requires a PCjr or ");
  5457.                    printf("a Tandy 1000 system.\n");
  5458.                    exit(1);
  5459.                    }
  5460.  
  5461.                 printf("2048 Hz periodic noise...\n");
  5462.                 fg_voice(4,2,15,3);
  5463.                 fg_waitfor(18);
  5464.  
  5465.                 printf("2048 Hz white noise...\n");
  5466.                 fg_voice(5,2,15,3);
  5467.                 fg_waitfor(18);
  5468.  
  5469.                 printf("500 Hz tone of increasing volume...\n");
  5470.                 for (volume = 1; volume <= 15; volume++) {
  5471.                    fg_voice(1,500,volume,0);
  5472.                    fg_waitfor(4);
  5473.                    }
  5474.  
  5475.                 fg_quiet();
  5476.              }
  5477.  
  5478.      Note how example 13-2 uses a duration of zero (continuous sound) and the
  5479. fg_waitfor routine to specify the duration for each volume level the 500
  5480. Hertz tone sequence.  This causes the transition between changes in volume to
  5481. blend better with each other.  The fg_quiet routine, which stops continuous
  5482. sound started with the fg_sound or fg_voice routines, ends the sound after
  5483. the final volume level.
  5484.  
  5485.      The fg_sound and fg_voice routines each produce a single sound.  We've
  5486. seen how to combine sounds to produce sound effects, but still the individual
  5487. sounds are defined numerically -- that is, by a certain frequency and
  5488. duration.  It is often easier to create sounds from musical notes, and for
  5489. this reason Fastgraph includes a routine fg_music that produces such sounds.
  5490. The fg_music routine uses the programmable timer to produce synchronous
  5491. sound; it does not support the TI sound chip.
  5492.  
  5493.      The fg_music routine has a single argument called the music string,
  5494. passed by reference as a byte array or character string.  The music string is
  5495. simply a variable-length sequence of music commands, followed by a dollar-
  5496. sign ($) terminator.  Music commands are summarized in the following table.
  5497.  
  5498.                command   meaning
  5499.  
  5500.                A thru G  Play the specified note in the current
  5501.                          octave.
  5502.  
  5503.                #         May be appended to a note character (A
  5504.                          through G) to make that note sharp.
  5505.  
  5506.                .         May be appended to a note character (A
  5507.                          through G) or a sharp (#) to extend that note
  5508.                          by half its normal length.  Multiple dots may
  5509.                          be used, and each will again extend the note
  5510.                          by half as much as the previous extension.
  5511. 238  Fastgraph User's Guide
  5512.  
  5513.                Ln        Set the length of subsequent notes and
  5514.                          pauses.  The value of n is an integer between
  5515.                          1 and 64, where 1 indicates a whole note, 2 a
  5516.                          half note, 4 a quarter note, and so forth.
  5517.                          If no L command is present, L4 is assumed.
  5518.  
  5519.                On        Set the octave for subsequent notes.  The
  5520.                          value of n may be an integer between 0 and 6
  5521.                          to set a specific octave.  It also can be a
  5522.                          plus (+) or minus (-) character to increment
  5523.                          or decrement the current octave number.
  5524.                          Octave 4 contains middle C, and if no O
  5525.                          command is present, O4 is assumed.
  5526.  
  5527.                P         Pause (rest) for the duration specified by
  5528.                          the most recent L command.
  5529.  
  5530.                Sn        Set the amount of silence between notes.  The
  5531.                          value of n is an integer between 0 and 2.  If
  5532.                          n is 0, each note plays for the full period
  5533.                          set by the L command (music legato).  If n is
  5534.                          1, each note plays for 7/8 the period set by
  5535.                          the L command (music normal).  If n is 2,
  5536.                          each note plays for 3/4 the period set by the
  5537.                          L command (music staccato).  If no S command
  5538.                          is present, S1 is assumed.
  5539.  
  5540.                Tn        Set the tempo of the music (the number of
  5541.                          quarter notes per minute).  The value of n is
  5542.                          an integer between 32 and 255.  If no T
  5543.                          command is present, T120 is assumed.
  5544.  
  5545. The fg_music routine ignores any other characters in the music string.  It
  5546. also ignores command values outside the allowable range, such as T20 or O8.
  5547.  
  5548.      Example 13-3 illustrates some uses of the fg_music routine.  The program
  5549. plays the first few bars of "Mary Had a Little Lamb", followed by the musical
  5550. scale (including sharps) in two octaves, and finally the introduction to
  5551. Beethoven's Fifth Symphony.  There is a pause of one second between each
  5552. piece of music, and the program displays the titles before playing the music.
  5553. Blank characters appear in the music strings to help make them more readable.
  5554.  
  5555.                                 Example 13-3.
  5556.  
  5557.     #include <fastgraf.h>
  5558.     #include <stdio.h>
  5559.     void main(void);
  5560.  
  5561.     void main()
  5562.     {
  5563.        printf("Mary Had a Little Lamb...\n");
  5564.        fg_music("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$");
  5565.        fg_waitfor(18);
  5566.  
  5567.        printf("up the scale in two octaves...\n");
  5568.        fg_music("L16 CC#DD#EFF#GG#AA#B O+ CC#DD#EFF#GG#AA#B$");
  5569.  
  5570.                                                Chapter 13:  Sound Effects  239
  5571.  
  5572.        fg_waitfor(18);
  5573.  
  5574.        printf("Beethoven's Fifth Symphony...\n");
  5575.        fg_music("T180 O2 L2 P L8 P GGG L2 D# L24 P L8 P FFF L2 D$");
  5576.     }
  5577.  
  5578.  
  5579.  
  5580.  
  5581. Asynchronous Sound
  5582.  
  5583.      Sounds made concurrently with other activity in a program are said to be
  5584. asynchronous.  Fastgraph's routines that produce asynchronous sound just
  5585. start the sound and then immediately return control to the calling program.
  5586. The sounds will automatically stop when the end of the sequence is reached,
  5587. and you also can suspend or stop it on demand before that time.  None of
  5588. Fastgraph's asynchronous sound routines have any effect if there is already
  5589. asynchronous sound in progress.  In addition, the asynchronous sound routines
  5590. temporarily disable the synchronous sound routines (fg_sound, fg_voice, and
  5591. fg_music) while asynchronous sound is in progress.
  5592.  
  5593.      To expand the range of sound effects and to play fast-tempo music,
  5594. Fastgraph temporarily quadruples the clock tick interrupt rate from 18.2 to
  5595. 72.8 ticks per second while producing asynchronous sound.  Because many disk
  5596. controllers rely on the 18.2 tick per second clock rate to synchronize disk
  5597. accesses, your programs should not perform any disk operations when
  5598. asynchronous sound is in progress.
  5599.  
  5600.      The fg_sounds routine is the asynchronous version of the fg_sound
  5601. routine.  It uses the programmable timer to play a sequence of tones
  5602. simultaneous to other operations.  This routine expects as its first argument
  5603. a variable-length integer array, passed by reference, containing pairs of
  5604. frequency and duration values.  As with the fg_sound routine, each frequency
  5605. is expressed in Hertz and must be between 18 and 32,767.  The durations are
  5606. also measured in clock ticks, but because the interrupt rate is quadrupled,
  5607. there are 72.8 instead of 18.2 ticks per second.
  5608.  
  5609.      The format of the frequency and duration array passed to fg_sounds is
  5610. shown below.
  5611.  
  5612.                           [0]    frequency of sound 1
  5613.  
  5614.                           [1]    duration  of sound 1
  5615.  
  5616.                           [2]    frequency of sound 2
  5617.  
  5618.                           [3]    duration  of sound 2
  5619.                                            .
  5620.                                            .
  5621.                                            .
  5622.                        [2n-2]    frequency of sound n
  5623.  
  5624.                        [2n-1]    duration  of sound n
  5625.  
  5626.                          [2n]       terminator (0)
  5627.  
  5628. 240  Fastgraph User's Guide
  5629.  
  5630.  
  5631. Note that a null character (that is, a zero byte) terminates the array.  The
  5632. second argument passed to fg_sounds is an integer value indicating the number
  5633. of times to cycle through the frequency and duration array.  If this value is
  5634. negative, the sounds will continue until stopped with the fg_hush or
  5635. fg_hushnext routines.
  5636.  
  5637.      Example 13-4 uses the fg_sounds routine to play the 100 to 500 Hertz
  5638. sliding tone sequence of example 13-1.  To prove the sounds are being made
  5639. concurrently with other operations, messages are displayed while the sequence
  5640. is playing.  This is controlled by the Fastgraph routine fg_playing, which
  5641. returns a value of 1 if asynchronous sounds are in progress, and 0 if not.
  5642. Note how the duration must be specified as 8 clock ticks (instead of 2 as in
  5643. example 13-1) to compensate for the quadrupled clock tick interrupt rate.
  5644.  
  5645.                                 Example 13-4.
  5646.  
  5647.                  #include <fastgraf.h>
  5648.                  #include <stdio.h>
  5649.                  void main(void);
  5650.  
  5651.                  void main()
  5652.                  {
  5653.                     int i;
  5654.                     int freq;
  5655.                     int sound_array[83];
  5656.  
  5657.                     i = 0;
  5658.  
  5659.                     for (freq = 100; freq <= 500; freq+=10) {
  5660.                        sound_array[i++] = freq;
  5661.                        sound_array[i++] = 8;
  5662.                        }
  5663.                     sound_array[i] = 0;
  5664.  
  5665.                     fg_sounds(sound_array,1);
  5666.  
  5667.                     while(fg_playing())
  5668.                        printf("Still playing...\n");
  5669.                  }
  5670.  
  5671.      Just as the fg_sounds routine is analogous to the fg_sound routine,
  5672. there is a Fastgraph routine fg_voices that is similar to the fg_voice
  5673. routine.  That is, fg_voices uses the TI sound chip to play an asynchronous
  5674. sequence of tones.  Its arguments are the same as those of the fg_sounds
  5675. routine, but the structure of the sound array is different.  Its structure
  5676. is:
  5677.  
  5678.  
  5679.                           [0]    channel # of sound 1
  5680.  
  5681.                           [1]    frequency of sound 1
  5682.  
  5683.                           [2]    volume    of sound 1
  5684.  
  5685.                           [3]    duration  of sound 1
  5686.  
  5687.                                                Chapter 13:  Sound Effects  241
  5688.  
  5689.                        [4n-4]    channel # of sound n
  5690.  
  5691.                        [4n-3]    frequency of sound n
  5692.  
  5693.                        [4n-2]    volume    of sound n
  5694.  
  5695.                        [4n-1]    duration  of sound n
  5696.  
  5697.                          [4n]       terminator (0)
  5698.  
  5699.  
  5700. The channel numbers, frequencies, volumes, and durations must be in the same
  5701. ranges as discussed in the description of the fg_voice routine, except the
  5702. durations are quadrupled because of the accelerated clock tick interrupt
  5703. rate.  Again, note that a null character (that is, a zero byte) terminates
  5704. the array.
  5705.  
  5706.      Example 13-5 uses the fg_voices routine to play the 500 Hertz tone
  5707. sequence of increasing volume introduced in example 13-2.  As in example
  5708. 13-4, the program displays messages while the tone sequence is playing to
  5709. demonstrate the sounds are being made concurrently with other operations.
  5710. Note how the duration is now 16 clock ticks (instead of 4 as in example 13-2)
  5711. because of the quadrupled clock tick interrupt rate.
  5712.  
  5713.                                 Example 13-5.
  5714.  
  5715.            #include <fastgraf.h>
  5716.            #include <stdio.h>
  5717.            void main(void);
  5718.  
  5719.            void main()
  5720.            {
  5721.               int voice_array[61];
  5722.               int i;
  5723.               int volume;
  5724.  
  5725.               if (fg_testmode(9,0) == 0) {
  5726.                  printf("This program requires a PCjr or ");
  5727.                  printf("a Tandy 1000 system.\n");
  5728.                  exit(1);
  5729.                  }
  5730.  
  5731.               i = 0;
  5732.  
  5733.               for (volume = 1; volume <= 15; volume++) {
  5734.                  voice_array[i++] = 1;      /* use channel 1 */
  5735.                  voice_array[i++] = 500;    /* 500 Hz frequency */
  5736.                  voice_array[i++] = volume; /* variable volume */
  5737.                  voice_array[i++] = 16;     /* duration */
  5738.                  }
  5739.               voice_array[i] = 0;
  5740.  
  5741.               fg_voices(voice_array,1);
  5742.  
  5743. 242  Fastgraph User's Guide
  5744.  
  5745.  
  5746.               while(fg_playing())
  5747.                  printf("Still playing...\n");
  5748.            }
  5749.  
  5750.  
  5751.      There is also an asynchronous version of the fg_music routine.  It is
  5752. called fg_musicb, and it uses the same format music string as the fg_music
  5753. routine does.  However, the fg_musicb routine has a second argument that
  5754. specifies the number of times to cycle through the music string.  If this
  5755. value is negative, the music will play repetitively until you stop it with
  5756. the fg_hush or fg_hushnext routine.
  5757.  
  5758.      Example 13-6 plays the same three pieces of music as example 13-3, but
  5759. it does so concurrently with other operations.  As the music plays, the
  5760. program continuously displays the title of each piece.  Note how we can take
  5761. advantage of the repetition in the music string for the "up the scale"
  5762. sequence by playing the sequence twice.
  5763.  
  5764.                                 Example 13-6.
  5765.  
  5766.   #include <fastgraf.h>
  5767.   #include <stdio.h>
  5768.   void main(void);
  5769.  
  5770.   void main()
  5771.   {
  5772.      fg_musicb("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$",1);
  5773.      while (fg_playing())
  5774.         printf("Mary Had a Little Lamb...\n");
  5775.      fg_waitfor(18);
  5776.  
  5777.  
  5778.      fg_musicb("L16 CC#DD#EFF#GG#AA#B O+$",2);
  5779.      while (fg_playing())
  5780.         printf("up the scale in two octaves...\n");
  5781.      fg_waitfor(18);
  5782.  
  5783.      fg_musicb("T180 O2 L2 P L8 P GGG L2 D# L24 P L8 P FFF L2 D$",1);
  5784.      while (fg_playing())
  5785.         printf("Beethoven's Fifth Symphony...\n");
  5786.   }
  5787.  
  5788.      The next example demonstrates the effects of the Fastgraph routines
  5789. fg_hush and fg_hushnext, which stop sounds started with the fg_sounds,
  5790. fg_voices, or fg_musicb routines.  The fg_hush routine immediately stops
  5791. asynchronous sound, whereas the fg_hushnext routine does so when the current
  5792. cycle finishes.  Neither routine has any arguments, and neither routine has
  5793. any effect if no asynchronous sound is in progress.  Furthermore, note that
  5794. fg_hushnext has no effect unless the asynchronous sound is continuous.
  5795.  
  5796.      Example 13-7 runs in any text or graphics video mode.  It displays
  5797. rectangles in up to 16 colors while playing continuous asynchronous music.
  5798. The program periodically checks for keystrokes with the fg_intkey routine,
  5799. and it continues to play the music while there is no keyboard activity.  If
  5800. you press the Escape key, the program uses fg_hush to stop the music
  5801. immediately; this causes an exit from the while loop.  If you press any other
  5802.                                                Chapter 13:  Sound Effects  243
  5803.  
  5804. key, the program uses fg_hushnext to stop the music as soon as the current
  5805. repetition finishes.  Once it does, the program exits the while loop because
  5806. fg_playing will return a value of zero.
  5807.  
  5808.                                 Example 13-7.
  5809.  
  5810.       #include <fastgraf.h>
  5811.       void main(void);
  5812.  
  5813.       #define ESC 27
  5814.  
  5815.       void main()
  5816.       {
  5817.          int color;
  5818.          int old_mode;
  5819.          unsigned char key, aux;
  5820.  
  5821.          old_mode = fg_getmode();
  5822.          fg_setmode(fg_automode());
  5823.          color = 0;
  5824.  
  5825.          fg_musicb("O4 L16 CC#DD#EFF#GG#AA#B O+ CC#DD#EFF#GG#AA#B$",-1);
  5826.  
  5827.          while (fg_playing())
  5828.          {
  5829.             color = (color + 1) & 15;
  5830.             fg_setcolor(color);
  5831.             fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  5832.  
  5833.             fg_waitfor(4);
  5834.             fg_intkey(&key,&aux);
  5835.             if (key == ESC)
  5836.                fg_hush();
  5837.             else if (key+aux != 0)
  5838.                fg_hushnext();
  5839.          }
  5840.  
  5841.          fg_setmode(old_mode);
  5842.          fg_reset();
  5843.       }
  5844.  
  5845.  
  5846.      Example 13-7 also demonstrates an important side-effect of the fg_musicb
  5847. routine when playing continuous music.  Any length, octave, silence, or tempo
  5848. values changed within the string are not reset to their original values at
  5849. the beginning of each repetition.  If we did not include the O4 command at
  5850. the beginning of the string, the later O+ command would cause the music to
  5851. play in octaves 4 and 5 during the first repetition, 5 and 6 during the
  5852. second repetition, and octave 6 for all subsequent repetitions (because you
  5853. cannot increase the octave number above 6).
  5854.  
  5855.      The final two routines relating to asynchronous sound are fg_resume and
  5856. fg_suspend.  The fg_suspend routine suspends music previously started by
  5857. fg_musicb, while fg_resume restarts the music from the point where it was
  5858. suspended.  Example 13-8 plays the first few bars of "Mary Had a Little
  5859. Lamb".  If you press any key while the song is playing, it stops.  Then,
  5860. after another keystroke, the music resumes and continues until finished.
  5861. 244  Fastgraph User's Guide
  5862.  
  5863.                                 Example 13-8.
  5864.  
  5865.   #include <fastgraf.h>
  5866.   #include <stdio.h>
  5867.   void main(void);
  5868.  
  5869.   void main()
  5870.   {
  5871.      fg_musicb("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$",1);
  5872.      fg_waitkey();
  5873.  
  5874.      fg_suspend();
  5875.      printf("Music suspended.  Press any key to resume.\n");
  5876.      fg_waitkey();
  5877.  
  5878.      fg_resume();
  5879.      printf("Music resumed.\n");
  5880.      while (fg_playing());
  5881.      printf("Music finished.\n");
  5882.   }
  5883.  
  5884.  
  5885. The fg_suspend routine has no effect if there is no asynchronous music in
  5886. progress.  Similarly, fg_resume has no effect if there is no suspended music.
  5887. If you call fg_suspend and then need to cancel the music or exit to DOS
  5888. instead of restarting the music, call fg_hush instead of fg_resume.
  5889.  
  5890.  
  5891. Summary of Sound Routines
  5892.  
  5893.      This section summarizes the functional descriptions of the Fastgraph
  5894. routines presented in this chapter.  More detailed information about these
  5895. routines, including their arguments and return values, may be found in the
  5896. Fastgraph Reference Manual.
  5897.  
  5898.      FG_HUSH immediately stops asynchronous sound started with the fg_sounds,
  5899. fg_voices, or fg_musicb routines.
  5900.  
  5901.      FG_HUSHNEXT is similar to fg_hush, but it does not stop the asynchronous
  5902. sound until the current repetition finishes.
  5903.  
  5904.      FG_MUSIC uses the programmable timer to play a sequence of musical
  5905. tones.
  5906.  
  5907.      FG_MUSICB is the asynchronous version of the fg_music routine.  It uses
  5908. the programmable timer to play a sequence of musical tones, concurrent with
  5909. other activity.
  5910.  
  5911.      FG_PLAYING determines whether or not there is any asynchronous sound in
  5912. progress.
  5913.  
  5914.      FG_QUIET stops continuous synchronous sound started with the fg_sound or
  5915. fg_voice routines.
  5916.  
  5917.      FG_RESUME restarts asynchronous music previously suspended by
  5918. fg_suspend.
  5919.                                                Chapter 13:  Sound Effects  245
  5920.  
  5921.      FG_SOUND produces a tone of a specified frequency and duration using the
  5922. programmable timer.
  5923.  
  5924.      FG_SOUNDS is the asynchronous version of the fg_sound routine.  It can
  5925. play a series of tones of specified frequencies and durations, concurrent
  5926. with other activity.
  5927.  
  5928.      FG_SUSPEND suspends asynchronous music previously started by fg_musicb.
  5929.  
  5930.      FG_VOICE produces a tone of a specified frequency, duration, and volume
  5931. using one of the TI sound chip's four voice channels.
  5932.  
  5933.      FG_VOICES is the asynchronous version of the fg_voice routine.  It can
  5934. play a series of tones of specified frequencies, durations, and volumes,
  5935. concurrent with other activity.
  5936. 246  Fastgraph User's Guide
  5937.  
  5938.  
  5939. Chapter 14
  5940.  
  5941. Program Timing
  5942. 248  Fastgraph User's Guide
  5943.  
  5944.  
  5945. Overview
  5946.  
  5947.      It is occasionally necessary to delay a program's execution for a brief
  5948. period, or to determine how long it takes to execute specific sections of a
  5949. program.  Fastgraph includes routines to accomplish these tasks.  Some of
  5950. these routines are said to be real-time, which means they are independent of
  5951. a system's processor speed, while the speed of others is processor-specific.
  5952. This chapter describes both classes of timing routines, all of which are
  5953. independent of the other parts of Fastgraph.
  5954.  
  5955.  
  5956. Real-Time Routines
  5957.  
  5958.      Real-time operations center around the BIOS time-of-day clock, which is
  5959. nothing more than a counter that the system automatically increments 18.2
  5960. times per second.  This number is often called the clock tick interrupt rate
  5961. because an interrupt routine performs the incrementing.  In addition, each
  5962. increment is usually called a clock tick.
  5963.  
  5964.      The Fastgraph routine fg_waitfor delays a program's execution by the
  5965. number of clock ticks specified as its argument.  Because fg_waitfor uses
  5966. clock ticks, the actual length of the delay is the same, regardless of the
  5967. system's processor speed.  Even when Fastgraph's asynchronous sound routines
  5968. quadruple the clock tick interrupt rate, Fastgraph compensates for this
  5969. internally so fg_waitfor always works as though the actual rate were still
  5970. 18.2 times per second.
  5971.  
  5972.      Example 14-1 displays a message every five seconds that states how long
  5973. the program has been running.  The fg_waitfor routine produces the five-
  5974. second delay by pausing 91 (18.2 times 5) clock ticks before the program
  5975. displays each message.  The program returns to DOS when you press any key.
  5976.  
  5977.                                 Example 14-1.
  5978.  
  5979.              #include <fastgraf.h>
  5980.              #include <stdio.h>
  5981.              void main(void);
  5982.  
  5983.              void main()
  5984.              {
  5985.                 unsigned int seconds;
  5986.                 unsigned char key, aux;
  5987.  
  5988.                 seconds = 0;
  5989.  
  5990.                 do {
  5991.                    fg_waitfor(91);
  5992.                    seconds += 5;
  5993.                    printf("%u seconds have elapsed.\n",seconds);
  5994.                    fg_intkey(&key,&aux);
  5995.                 }
  5996.                 while (key+aux == 0);
  5997.              }
  5998.  
  5999.      Another common application of the fg_waitfor routine is to slow down a
  6000. loop that uses the fg_intkey routine to check for keystrokes.  In loops that
  6001.                                               Chapter 14:  Program Timing  249
  6002.  
  6003. do little else, we may call fg_intkey too rapidly without this delay, and it
  6004. is then possible that the BIOS may not be able to store characters in its
  6005. keyboard buffer fast enough.  A small delay, even one clock tick, often helps
  6006. such "tight" loops.
  6007.  
  6008.      The fg_getclock routine provides an efficient way to measure time,
  6009. especially differences in time.  This routine has no arguments and returns a
  6010. 32-bit unsigned integer (as its function value) representing the number of
  6011. clock ticks since midnight.  Example 14-2 demonstrates the fg_getclock
  6012. routine.  In response to any keystroke (except Escape, which returns control
  6013. to DOS), the program displays the number of clock ticks since midnight, and
  6014. the number of ticks since the program started.
  6015.  
  6016.                                 Example 14-2.
  6017.  
  6018.       #include <fastgraf.h>
  6019.       #include <stdio.h>
  6020.       void main(void);
  6021.  
  6022.       #define ESC 27
  6023.  
  6024.       void main()
  6025.       {
  6026.          unsigned long start, ticks;
  6027.          unsigned char key, aux;
  6028.  
  6029.          start = fg_getclock();
  6030.  
  6031.          do {
  6032.             ticks = fg_getclock();
  6033.             printf("%lu ticks since midnight.\n",ticks);
  6034.             printf("%lu ticks since start of program.\n\n",ticks-start);
  6035.             fg_getkey(&key,&aux);
  6036.          }
  6037.          while (key != ESC);
  6038.       }
  6039.  
  6040.  
  6041.  
  6042. Routines Dependent on the System Speed
  6043.  
  6044.      The fg_waitfor routine described in the previous section is independent
  6045. of the system's processor speed.  This means the actual length of its delay
  6046. is the same on any system.  Another routine, fg_stall, is similar to
  6047. fg_waitfor, but its delay is proportional to the processor speed.  Like
  6048. fg_waitfor, fg_stall has a single integer argument that specifies the length
  6049. of the delay.  However, instead of being expressed in clock ticks, fg_stall
  6050. measures the delay in delay units.  The fg_stall routine treats the length as
  6051. an unsigned quantity, so the maximum number of delay units we can specify is
  6052. 65,535.  The following table lists the approximate number of delay units per
  6053. clock tick on three typical systems.
  6054. 250  Fastgraph User's Guide
  6055.  
  6056.                         system         delay units
  6057.                         type           per clock tick
  6058.  
  6059.                         Tandy 1000 HX        675
  6060.                         10 MHz 80286       3,000
  6061.                         25 MHz 80386      11,000
  6062.  
  6063.      Fastgraph includes a routine that determines the number of delay units
  6064. per clock tick for the processor being used.  This is the fg_measure routine,
  6065. which has no arguments and returns the number of delay units per clock tick
  6066. as its function value.  Once we determine this value, we can use fg_stall to
  6067. delay a program's execution in real time.  This provides a much more refined
  6068. delay than the clock tick unit used by fg_waitfor.
  6069.  
  6070.      Example 14-3 is functionally identical to example 14-1, but it uses the
  6071. fg_stall routine instead of fg_waitfor to delay the program execution.  The
  6072. program first calls the fg_measure routine to determine number of delay units
  6073. equivalent to one clock tick.  It then passes this value to fg_stall, called
  6074. 91 times inside the for loop to create the five-second delay (because 91
  6075. clock ticks equals five seconds).  The program returns to DOS when you press
  6076. any key.
  6077.  
  6078.                                 Example 14-3.
  6079.  
  6080.              #include <fastgraf.h>
  6081.              #include <stdio.h>
  6082.              void main(void);
  6083.  
  6084.              void main()
  6085.              {
  6086.                 int i;
  6087.                 int units_per_tick;
  6088.                 unsigned int seconds;
  6089.                 unsigned char key, aux;
  6090.  
  6091.                 seconds = 0;
  6092.  
  6093.                 printf("Benchmarking system speed...\n");
  6094.                 units_per_tick = fg_measure();
  6095.                 printf("Benchmark completed.\n\n");
  6096.  
  6097.                 do {
  6098.                    for (i = 0; i < 91; i++)
  6099.                       fg_stall(units_per_tick);
  6100.                    seconds += 5;
  6101.                    printf("%u seconds have elapsed.\n",seconds);
  6102.                    fg_intkey(&key,&aux);
  6103.                 }
  6104.                 while (key+aux == 0);
  6105.              }
  6106.  
  6107.  
  6108.      One final point:  the fg_measure routine takes a few seconds to
  6109. benchmark the system speed accurately.  For this reason, you should only call
  6110. fg_measure once (typically at the beginning of the program) and use its
  6111. return value instead of calling fg_measure throughout the program.
  6112.                                               Chapter 14:  Program Timing  251
  6113.  
  6114.  
  6115. Summary of Timing Routines
  6116.  
  6117.      This section summarizes the functional descriptions of the Fastgraph
  6118. routines presented in this chapter.  More detailed information about these
  6119. routines, including their arguments and return values, may be found in the
  6120. Fastgraph Reference Manual.
  6121.  
  6122.      FG_GETCLOCK returns the number of clock ticks since midnight as its
  6123. function value.  This quantity is a 32-bit unsigned integer.
  6124.  
  6125.      FG_MEASURE returns the approximate number of delay units per clock tick
  6126. as its function value.  This quantity is proportional to the system's
  6127. processor speed.
  6128.  
  6129.      FG_STALL delays a program's execution for a given number of processor-
  6130. specific delay units.
  6131.  
  6132.      FG_WAITFOR delays a program's execution for a given number of clock
  6133. ticks.  There are 18.2 clock ticks per second, regardless of the system's
  6134. processor speed.
  6135. 252  Fastgraph User's Guide
  6136.  
  6137.  
  6138. Chapter 15
  6139.  
  6140. Miscellaneous Routines
  6141. 254  Fastgraph User's Guide
  6142.  
  6143. Overview
  6144.  
  6145.      There are a few remaining Fastgraph routines that really don't fit into
  6146. any of the categories discussed so far.  For this reason, they are described
  6147. separately in this chapter.
  6148.  
  6149.  
  6150. Determining Available Memory
  6151.  
  6152.      The fg_memavail routine returns the amount of free conventional memory
  6153. (in bytes) available to DOS.  It returns the amount of memory as its function
  6154. value, which is a 32-bit unsigned integer.  Fg_memavail has no arguments.
  6155.  
  6156.      Example 15-1 uses fg_memavail to show the effects of creating and
  6157. releasing virtual pages.  When run in a video mode in which video pages 1 and
  6158. 2 are physical pages, the amount of free memory remains the same because
  6159. these pages use memory that is resident on the video adapter.  However, in
  6160. modes where pages 1 and 2 are virtual pages, the amount of free memory
  6161. decreases after each call to fg_allocate and returns to its original value
  6162. after the calls to fg_freepage.  Note how the program requests and validates
  6163. the video mode.
  6164.  
  6165.                                 Example 15-1.
  6166.  
  6167.        #include <fastgraf.h>
  6168.        #include <stdio.h>
  6169.        #include <stdlib.h>
  6170.        void main(void);
  6171.  
  6172.        void main()
  6173.        {
  6174.           long original, mem0, mem1, mem2;
  6175.           int  mode, old_mode;
  6176.  
  6177.           printf("Which video mode? ");
  6178.           scanf("%d",&mode);
  6179.  
  6180.           if (fg_testmode(mode,0) == 0) {
  6181.              printf("Your system does not support that video mode.\n");
  6182.              exit(1);
  6183.              }
  6184.           if (fg_testmode(mode,3) == 0) {
  6185.              printf("Your system does not have enough memory.\n");
  6186.              exit(1);
  6187.              }
  6188.  
  6189.           original = fg_memavail();
  6190.           old_mode = fg_getmode();
  6191.           fg_setmode(mode);
  6192.           mem0 = fg_memavail();
  6193.           fg_allocate(1);
  6194.           mem1 = fg_memavail();
  6195.           fg_allocate(2);
  6196.           mem2 = fg_memavail();
  6197.           fg_freepage(1);
  6198.           fg_freepage(2);
  6199.  
  6200.                                       Chapter 15:  Miscellaneous Routines  255
  6201.  
  6202.           fg_setmode(old_mode);
  6203.           fg_reset();
  6204.  
  6205.           printf("originally     = %ld\n",original);
  6206.           printf("after setmode  = %ld\n",mem0);
  6207.           printf("after 1st page = %ld\n",mem1);
  6208.           printf("after 2nd page = %ld\n",mem2);
  6209.           printf("at end         = %ld\n",memavail());
  6210.        }
  6211.  
  6212.  
  6213.  
  6214. Choosing the Video Memory Update Function
  6215.  
  6216.      In Chapter 10, we saw how to use the fg_setfunc routine to perform XOR
  6217. animation in native EGA and VGA graphics modes (modes 13 to 18).  In these
  6218. video modes, fg_setfunc controls the logical operation applied when the
  6219. contents of video memory change.  The specific operation is defined by its
  6220. argument, as shown below.
  6221.  
  6222.                           value of  logical
  6223.                           argument  operation
  6224.  
  6225.                               0     replacement
  6226.                               1     and
  6227.                               2     or
  6228.                               3     exclusive or
  6229.  
  6230. If your program does not use the fg_setfunc routine, replacement mode is
  6231. always used.  That is, information written to video memory replaces whatever
  6232. was there before.  The fg_setfunc routine does nothing in CGA, Tandy/PCjr,
  6233. Hercules, or MCGA graphics modes, or in any text modes.
  6234.  
  6235.      Example 15-2 demonstrates the fg_setfunc routine.  The program is
  6236. similar to example 6-10 which displays 200 random rectangles on the screen.
  6237. However, example 15-2 displays the rectangles in XOR mode, which means the
  6238. rectangle intersections will appear in different colors.
  6239.  
  6240.                                 Example 15-2.
  6241.  
  6242.             #include <fastgraf.h>
  6243.             #include <stdio.h>
  6244.             #include <stdlib.h>
  6245.             void main(void);
  6246.  
  6247.             #define RECTANGLES 200
  6248.             #define SWAP(a,b,temp) { temp = a; a = b; b = temp; }
  6249.  
  6250.             void main()
  6251.             {
  6252.                int i;
  6253.                int minx, maxx, miny, maxy;
  6254.                int old_mode;
  6255.                int temp;
  6256.  
  6257. 256  Fastgraph User's Guide
  6258.  
  6259.                int xres, yres;
  6260.  
  6261.                if (fg_egacheck() == 0) {
  6262.                   printf("This program requires EGA or VGA.\n");
  6263.                   exit(1);
  6264.                   }
  6265.  
  6266.                old_mode = fg_getmode();
  6267.                fg_setmode(fg_automode());
  6268.                fg_setfunc(3);
  6269.  
  6270.                xres = fg_getmaxx() + 1;
  6271.                yres = fg_getmaxy() + 1;
  6272.  
  6273.                for (i = 0; i < RECTANGLES; i++) {
  6274.                   minx = rand() % xres;
  6275.                   maxx = rand() % xres;
  6276.                   miny = rand() % yres;
  6277.                   maxy = rand() % yres;
  6278.                   if (minx > maxx)
  6279.                      SWAP(minx,maxx,temp);
  6280.                   if (miny > maxy)
  6281.                      SWAP(miny,maxy,temp);
  6282.                   fg_setcolor(rand()%16);
  6283.                   fg_rect(minx,maxx,miny,maxy);
  6284.                   }
  6285.  
  6286.                fg_setmode(old_mode);
  6287.                fg_reset();
  6288.             }
  6289.  
  6290.  
  6291.  
  6292. Summary of Miscellaneous Routines
  6293.  
  6294.      This section summarizes the functional descriptions of the Fastgraph
  6295. routines presented in this chapter.  More detailed information about these
  6296. routines, including their arguments and return values, may be found in the
  6297. Fastgraph Reference Manual.
  6298.  
  6299.      FG_MEMAVAIL returns the amount of memory available to DOS.
  6300.  
  6301.      FG_SETFUNC specifies the logical operation (replacement, or, and,
  6302. exclusive or) applied when video memory changes in the native EGA and VGA
  6303. graphics modes.  This routine has no effect in other video modes.
  6304.  
  6305.  
  6306. Appendix A
  6307.  
  6308. Fastgraph Utilities
  6309. 258  Fastgraph User's Guide
  6310.  
  6311.  
  6312. Overview
  6313.  
  6314.      This appendix describes utilities for creating and managing pixel run
  6315. files used with the fg_dispfile routine.  By default, the Fastgraph
  6316. installation procedure places these utilities in the \FG directory.  To use
  6317. these utilities, you must either (1) copy the .EXE file from \FG to your
  6318. current directory, (2) make \FG your current directory, or (3) include the
  6319. \FG directory in your DOS path specification.
  6320.  
  6321.  
  6322. SNAPSHOT Utility
  6323.  
  6324.      The SNAPSHOT utility is a terminate and stay resident program (TSR) to
  6325. capture graphic images.  It stores the image in Fastgraph's standard pixel
  6326. run format.  To load SNAPSHOT, just enter the command SNAPSHOT at the DOS
  6327. prompt, and you'll see messages similar to the following if SNAPSHOT loads
  6328. successfully.
  6329.  
  6330.  
  6331.         C> SNAPSHOT
  6332.  
  6333.         SNAPSHOT  Version 1.01
  6334.         Copyright (c) 1991 Ted Gruber Software.  All Rights Reserved.
  6335.  
  6336.         Press <alt>-<left shift> to activate.
  6337.  
  6338.  
  6339.      After SNAPSHOT loads, control returns to the DOS prompt.  At this point,
  6340. you can use any method whatsoever to display a graphic image and then press
  6341. the Alt and left shift keys at the same time to capture the image.  You don't
  6342. need to load SNAPSHOT for each image capture, just once per system boot.
  6343. SNAPSHOT uses about 14,000 bytes of conventional memory once loaded.
  6344.  
  6345.      To illustrate the use of SNAPSHOT, suppose you have drawn and saved an
  6346. image with a commercial paint program, and you want to incorporate this image
  6347. into a Fastgraph application.  Once you load SNAPSHOT, start the paint
  6348. program and retrieve your image.  Then press the Alt and left shift keys
  6349. simultaneously and wait for the success tone (three quick medium-pitched
  6350. sounds).  Finally, exit the paint program to return to the DOS prompt.
  6351.  
  6352.      The sequence described in the preceding paragraph will store the
  6353. captured image in Fastgraph's standard pixel run format, in a file named
  6354. SNAPSHOT.nnn in the current directory.  The file type nnn will be the first
  6355. sequence of digits that does not result in a duplicate file name.  That is,
  6356. if there are no captured image files in the current directory, SNAPSHOT will
  6357. use the file name SNAPSHOT.000.  The next time you capture an image, SNAPSHOT
  6358. will store it in SNAPSHOT.001, then SNAPSHOT.002, and so forth.  If you
  6359. rename or delete one of these files, SNAPSHOT will again use that file name.
  6360. For example, if you delete SNAPSHOT.000 but keep SNAPSHOT.001, SNAPSHOT will
  6361. store the next image it captures in SNAPSHOT.000.
  6362.  
  6363.      If SNAPSHOT is unable to capture the image, it will produce its error
  6364. tone (a single low-pitched sound).  The most common cause of this is trying
  6365. to capture an image from a text video mode, but it also will occur if there
  6366. is not enough disk space or if all 1,000 image file names are already being
  6367. used.
  6368.                                          Appendix A:  Fastgraph Utilities  259
  6369.  
  6370.  
  6371. CLIP Utility
  6372.  
  6373.      The SNAPSHOT utility described in the previous section captures the
  6374. entire screen.  While this might be desirable in some cases, other times
  6375. you'll just need a portion of the screen.  CLIP is an interactive utility
  6376. that you can use to reduce the size of any image stored in Fastgraph's
  6377. standard or packed pixel run format.  The syntax of the command for invoking
  6378. the CLIP utility from the DOS prompt is
  6379.  
  6380.                      CLIP input_file output_file options
  6381.  
  6382. where input_file is the name of the original image file, and output_file is
  6383. the name of the new image file.  CLIP does not modify the input_file in any
  6384. way, but it will overwrite the output_file if an identically named file
  6385. exists in the current directory.  The options list specifies one or more
  6386. optional switches as shown below.
  6387.  
  6388.  
  6389.                option         meaning
  6390.  
  6391.                /M:mode   Specifies the video mode number in which to
  6392.                          display the image.  The mode value must be an
  6393.                          integer between 0 and 23.  If that video mode
  6394.                          is a text mode, an unsupported graphics mode,
  6395.                          or an unavailable graphics mode, CLIP
  6396.                          displays an error message stating this.  If
  6397.                          the /M switch is not present, CLIP uses the
  6398.                          first available video mode from the list 16,
  6399.                          15, 19, 13, 9, 4, 12.
  6400.  
  6401.                /P        Indicates the input_file is in Fastgraph's
  6402.                          packed pixel run format.  If the /P switch is
  6403.                          not present, CLIP assumes it is in standard
  6404.                          pixel run format.  The output_file will be in
  6405.                          the same format as the input_file.
  6406.  
  6407.                /W:width  Specifies the image width in pixels.  The
  6408.                          width value must be an integer between 1 and
  6409.                          the horizontal resolution of the selected
  6410.                          video mode.  If the /W switch is not present,
  6411.                          CLIP uses the horizontal resolution of the
  6412.                          selected video mode.
  6413.  
  6414. For example, if you wanted to create the image file PARTIAL.PPR from the
  6415. packed pixel run file SCREEN.PPR, and use the native 320 by 200 EGA graphics
  6416. video mode (mode 13), you would start CLIP with the following command.
  6417.  
  6418.                      CLIP PARTIAL.PPR SCREEN.PPR /P /M:13
  6419.  
  6420. Because no /W switch appears in the above command and the horizontal
  6421. resolution of mode 13 is 320 pixels, CLIP assumes the image width is 320
  6422. pixels.
  6423. 260  Fastgraph User's Guide
  6424.  
  6425.  
  6426.      When CLIP displays the image and the plus-shaped cursor, you are ready
  6427. to define one corner of the clipping region (that part of the image used to
  6428. create the output_file).  To do this, use the directional keys on the numeric
  6429. keypad to move the cursor to the desired position, then press the Enter key.
  6430. You are then ready to define the clipping region's opposite corner.  Again,
  6431. use the directional keys to move the cursor to the desired position.  When
  6432. defining the second corner, however, CLIP uses a rectangular box instead of
  6433. the plus-shaped cursor to simplify marking the clipping region's boundaries.
  6434. After you press Enter to define the second corner, CLIP creates the
  6435. output_file and displays the resulting image width and the number of pixel
  6436. runs the image contains.
  6437.  
  6438.      CLIP includes some features that may help you define the clipping
  6439. region.  You can change the distance the cursor moves in response to the
  6440. directional keys, display the current (x,y) pixel coordinates of the cursor,
  6441. and change the cursor color.  The following table explains the keystrokes
  6442. that CLIP recognizes when you are defining the clipping region.
  6443.  
  6444.                key       meaning
  6445.  
  6446.                F1        Displays the (x,y) coordinate bar at the top
  6447.                          of the screen.  If the coordinate bar is
  6448.                          already on, F1 removes it.
  6449.                F2        Displays the (x,y) coordinate bar at the
  6450.                          bottom of the screen.  If the coordinate bar
  6451.                          is already on, F2 removes it.
  6452.                F3        Changes the cursor or box color from white to
  6453.                          black, or from black to white.
  6454.                F4        Displays a summary of the keys CLIP
  6455.                          recognizes when defining the clipping region.
  6456.                KP1       Moves the cursor one unit down and to the
  6457.                          left.
  6458.                KP2       Moves the cursor one unit down.
  6459.                KP3       Moves the cursor one unit down and to the
  6460.                          right.
  6461.                KP4       Moves the cursor one unit to the left.
  6462.                KP6       Moves the cursor one unit to the right.
  6463.                KP7       Moves the cursor one unit up and to the left.
  6464.                KP8       Moves the cursor one unit up.
  6465.                KP9       Moves the cursor one unit up and to the
  6466.                          right.
  6467.                +         Increases the unit of cursor movement by one
  6468.                          pixel.  The default cursor movement is one
  6469.                          pixel.
  6470.                -         Decreases the unit of cursor movement by one
  6471.                          pixel.
  6472.                Enter     Defines a corner of the clipping region
  6473.                          at the cursor position.
  6474.                Esc       Exits to DOS without creating the
  6475.                          output_file.  CLIP will first issue an "Exit
  6476.                          to DOS?" prompt in case you pressed the Esc
  6477.                          key accidentally.
  6478.                                          Appendix A:  Fastgraph Utilities  261
  6479.  
  6480.      The CLIP utility requires two video pages to run.  Thus, you cannot use
  6481. it in video modes 17, 18, and 23 because they have only one physical video
  6482. page and no virtual video pages.
  6483.  
  6484.  
  6485. CONVERT Utility
  6486.  
  6487.      The CONVERT utility lets you translate files between Fastgraph's
  6488. supported image file formats.  The syntax of the command for invoking CONVERT
  6489. from the DOS prompt is
  6490.  
  6491.                         CONVERT input_file output_file
  6492.  
  6493. where input_file is the name of the original image file, and output_file is
  6494. the name of the new translated image file.  CONVERT does not modify the
  6495. input_file in any way, but it will overwrite the output_file if an
  6496. identically named file exists in the current directory.
  6497.  
  6498.      By default, the file type of the input_file and output_file determine
  6499. the image format of that file.  If the file type is .PPR, CONVERT assumes the
  6500. image is in Fastgraph's packed pixel run format.  If the file type is .SPR,
  6501. CONVERT assumes it is in the Fastgraph's standard pixel run format.  If your
  6502. image files use other file types, you can explicitly specify the file's image
  6503. format by appending one of the switches /PPR or /SPR to the file name.  The
  6504. input_file and output_file must not both specify the same image format
  6505. (CONVERT will display an error message if this is so).
  6506.  
  6507.      The following command will translate the standard pixel run file
  6508. PICTURE.SPR to packed format.  The packed image will be stored in the file
  6509. PICTURE.IMG, so we must append the switch /PPR to tell CONVERT that it will
  6510. be a packed file.
  6511.  
  6512.                      CONVERT PICTURE.SPR PICTURE.IMG/PPR
  6513.  
  6514.  
  6515. EDITSPR Utility
  6516.  
  6517.      The EDITSPR utility changes all pixel runs of one color to another color
  6518. in an image file stored in Fastgraph's standard pixel run (.SPR) format.  The
  6519. syntax of the command for invoking the EDITSPR utility from the DOS command
  6520. prompt is
  6521.  
  6522.                         EDITSPR input_file output_file
  6523.  
  6524. where input_file is the name of the original image file, and output_file is
  6525. the name of the new image file.  EDITSPR does not modify the input_file in
  6526. any way, but it will overwrite the output_file if an identically named file
  6527. exists in the current directory.
  6528.  
  6529.      After it reads the pixel runs from the input_file, EDITSPR will perform
  6530. the requested color changes.  It does this iteratively by asking for an old
  6531. color value followed by a new color value (each value must be between 0 and
  6532. 262  Fastgraph User's Guide
  6533.  
  6534. 255).  EDITSPR then finds the pixel runs of the old color value and changes
  6535. them to the new color value.  Following this, EDITSPR displays a message
  6536. stating how many pixel runs it changed.  This process repeats until you enter
  6537. a negative number for either color value.
  6538.  
  6539.      EDITSPR will next combine adjacent pixel runs of like colors.  For
  6540. example, suppose the original image file contained a color 1 pixel run of
  6541. length 50, followed by a color 2 pixel run of length 20, followed by another
  6542. color 1 pixel run of length 10.  If you changed all color 2 pixel runs to
  6543. color 1, EDITSPR will combine these three pixel runs into a single run of
  6544. length 80.
  6545.  
  6546.      Finally, EDITSPR will close the output_file.
  6547.  
  6548.  
  6549. GrabRGB Utility
  6550.  
  6551.      The GrabRGB utility is a terminate and stay resident program (TSR) to
  6552. capture the current red, green, and blue color components of video DAC
  6553. registers in the 256-color MCGA and VGA graphics modes.  You can use GrabRGB
  6554. together with Fastgraph's SNAPSHOT utility to preserve the original colors of
  6555. a captured image.
  6556.  
  6557.      To load GrabRGB, just enter the command GRABRGB at the DOS prompt.
  6558. After GrabRGB loads, control returns to the DOS prompt.  At this point, you
  6559. can use any method whatsoever to display a 256-color graphic image and then
  6560. press the Alt and right shift keys at the same time to capture the current
  6561. DAC values.  You don't need to load GrabRGB for each image, just once per
  6562. system boot.  GrabRGB uses about 15,000 bytes of conventional memory once
  6563. loaded.
  6564.  
  6565.      To illustrate the use of GrabRGB, suppose you have drawn and saved a
  6566. 256-color image with a commercial paint program, and you want to incorporate
  6567. this image into a Fastgraph application.  Once you load SNAPSHOT and GrabRGB,
  6568. start the paint program and retrieve your image.  Then press the Alt and left
  6569. shift keys to capture the image with SNAPSHOT.  After SNAPSHOT's success tone
  6570. (three quick medium-pitched sounds), press Alt and right shift to capture the
  6571. RGB components of each DAC register with GrabRGB, and wait for GrabRGB's
  6572. success tone.  Finally, exit the paint program and return to the DOS prompt.
  6573.  
  6574.      The sequence described in the preceding paragraph will write the RGB
  6575. color components for each DAC register to a file named GRABRGB.nnn in the
  6576. current directory.  The file type nnn will be the first sequence of digits
  6577. that does not result in a duplicate file name.  That is, if there are no
  6578. GrabRGB output files in the current directory, GrabRGB will use the file name
  6579. GRABRGB.000.  The next time you use GrabRGB, it will store the RGB
  6580. information in GRABRGB.001, then GRABRGB.002, and so forth.  If you rename or
  6581. delete one of these files, GrabRGB will again use that file name.  For
  6582. example, if you delete GRABRGB.000 but keep GRABRGB.001, GrabRGB will next
  6583. use the file name GRABRGB.000.
  6584.  
  6585.      If GrabRGB is unable to obtain the RGB components of each DAC register,
  6586. it will produce its error tone (a single low-pitched sound).  The most common
  6587. cause of this is trying to capture an image from a text video mode, or from a
  6588. graphics video mode with fewer than 256 colors.  It also will occur if there
  6589. is not enough disk space or if all 1,000 output file names are already being
  6590. used.
  6591.                                          Appendix A:  Fastgraph Utilities  263
  6592.  
  6593.      Each line in the output file created by GrabRGB is of the form
  6594.  
  6595.                                 nnn,rr,gg,bb,
  6596.  
  6597. where nnn is a DAC register index (between 0 and 255), rr is the red
  6598. component of that DAC register, gg is the green component, and bb is the blue
  6599. component.  Each color component is between 0 and 63.  You can edit and
  6600. reformat these lines as necessary for inclusion in a C initializer list, a
  6601. QuickBASIC or FORTRAN data statement, or a Turbo Pascal array-type constant
  6602. list.  Such an array of RGB components, but without the nnn indices, is in
  6603. the format expected by fg_setdacs.
  6604.  
  6605.      By default, GrabRGB captures information for all 256 DAC registers.  If
  6606. you want to consider only the DAC registers with color components different
  6607. from their initial values, just include the /D option when you load GrabRGB
  6608. (that is, use the command GRABRGB /D).  If you specify the /D option and all
  6609. 256 DACs use their default values, the output file will contain a message
  6610. stating this.
  6611.  
  6612.  
  6613. HERCFIX Utility
  6614.  
  6615.      The HERCFIX utility allows you to use SNAPSHOT (and possibly other TSRs)
  6616. with programs that do not update the BIOS data area when establishing the
  6617. 720x348 Hercules graphics mode.  If you use SNAPSHOT with such a program, it
  6618. will think the monochrome text mode (video mode 7) is active and will produce
  6619. its low-pitched error tone when activated.
  6620.  
  6621.      If this occurs, use HERCFIX to load the application from which you are
  6622. trying to capture the image.  To do this, enter
  6623.  
  6624.                                HERCFIX command
  6625.  
  6626. at the DOS prompt, where command is the command that starts the application.
  6627. For example, suppose you use the command PAINTER /H to run a commercial paint
  6628. program in Hercules graphics mode.  To load the paint program with HERCFIX,
  6629. you would enter the command HERCFIX PAINTER /H.
  6630. 264  Fastgraph User's Guide
  6631.  
  6632.  
  6633. Appendix B
  6634.  
  6635. Using Fastgraph
  6636. from Assembly Language
  6637. 266  Fastgraph User's Guide
  6638.  
  6639.  
  6640.      Fastgraph uses the same naming and calling conventions as Microsoft C
  6641. and Turbo C.  The details of these conventions that are important to assembly
  6642. language programming are summarized below.  If you are calling Fastgraph
  6643. routines from an assembly language program, the program must follow these
  6644. conventions.
  6645.  
  6646.        All arrays and pointers are passed by reference
  6647.        All other items are passed by value
  6648.        Arguments are pushed onto the stack in reverse order
  6649.        16-bit function values are returned in the AX register
  6650.        32-bit function values are returned in the DX:AX register pair
  6651.        Fastgraph routine names are prefixed with an underscore character
  6652.  
  6653. The small and medium model Fastgraph libraries pass arrays and pointers by
  6654. near reference, while the large model library does so by far reference.  This
  6655. is consistent with the run-time libraries for the supported compilers.
  6656.  
  6657.      All Fastgraph routines preserve the BP, DS, DI, and SI registers.  The
  6658. contents of any other registers are unknown upon return from a Fastgraph
  6659. routine (except for the AX register, which will either contain zero or the
  6660. routine's return value).
  6661.  
  6662.      The following DOS commands show how to assemble a program (using the
  6663. Microsoft Macro Assembler) and then link it with Fastgraph.  In all cases,
  6664. we'll assume the file EXAMPLE.ASM contains the source code for the program.
  6665. The resulting executable file will be called EXAMPLE.EXE.
  6666.  
  6667.                               small memory model
  6668.  
  6669.                     MASM EXAMPLE.ASM;
  6670.                     LINK /CP:4096 /E EXAMPLE,,NUL.MAP,FGS
  6671.  
  6672.  
  6673.                              medium memory model
  6674.  
  6675.                     MASM EXAMPLE.ASM;
  6676.                     LINK /CP:4096 /E EXAMPLE,,NUL.MAP,FGM
  6677.  
  6678.  
  6679.                               large memory model
  6680.  
  6681.                     MASM EXAMPLE.ASM;
  6682.                     LINK /CP:4096 /E EXAMPLE,,NUL.MAP,FGL
  6683.  
  6684.  
  6685.      Example B-1 calls the fg_getmode, fg_setmode, fg_reset, and fg_version
  6686. routines from an assembly language program.  The fg_getmode routine returns
  6687. its function value in the AX register.  The fg_setmode routine has a single
  6688. argument, while fg_reset has no arguments.  The fg_version routine has two
  6689. arguments, both passed by reference.  Notice how they are pushed on the stack
  6690. in reverse order.  This example would work with either the medium or large
  6691. memory model Fastgraph libraries.  To make it work with the small model
  6692. library, all you would need to do is change the word "far" to "near" in the
  6693. EXTRN declarations, and change the name of the code segment from "main_TEXT"
  6694. to "_TEXT".
  6695.                       Appendix B:  Using Fastgraph from Assembly Language  267
  6696.  
  6697.  
  6698.                                  Example B-1.
  6699.  
  6700.                 EXTRN   _fg_getmode:far  ; Fastgraph's GETMODE routine
  6701.                 EXTRN   _fg_reset:far    ; Fastgraph's RESET routine
  6702.                 EXTRN   _fg_setmode:far  ; Fastgraph's SETMODE routine
  6703.                 EXTRN   _fg_version:far  ; Fastgraph's VERSION routine
  6704.  
  6705.       stackseg  SEGMENT stack         ; suppress the linker's
  6706.       stackseg  ENDS                  ; "no stack segment" error message
  6707.  
  6708.       _DATA     SEGMENT word public 'DATA'
  6709.  
  6710.       major     dw      ?             ; major version number
  6711.       minor     dw      ?             ; minor version number
  6712.       old_mode  dw      ?             ; original video mode
  6713.  
  6714.       _DATA     ENDS
  6715.  
  6716.       dgroup    GROUP   _DATA
  6717.                 ASSUME  cs:main_TEXT,ds:dgroup
  6718.  
  6719.       main_TEXT SEGMENT byte public 'CODE'
  6720.  
  6721.       start:    mov     ax,_DATA      ; load segment location
  6722.                 mov     ds,ax         ; into DS register
  6723.  
  6724.                 call    _fg_getmode   ; AX = current video mode
  6725.                 mov     old_mode,ax   ; save it
  6726.  
  6727.                 mov     ax,4          ; use video mode 4
  6728.                 push    ax            ; pass argument to SETMODE
  6729.                 call    _fg_setmode   ; establish CGA four-color mode
  6730.                 add     sp,2          ; remove SETMODE argument
  6731.  
  6732.                 push    old_mode      ; pass argument to SETMODE
  6733.                 call    _fg_setmode   ; restore original video mode
  6734.                 add     sp,2          ; remove SETMODE argument
  6735.  
  6736.                 call    _fg_reset     ; restore screen attributes
  6737.  
  6738.                 lea     ax,minor      ; get address of minor variable
  6739.                 push    ax            ; pass argument #2 to VERSION
  6740.                 lea     ax,major      ; get address of major variable
  6741.                 push    ax            ; pass argument #1 to VERSION
  6742.                 call    _fg_version   ; get the Fastgraph version number
  6743.                 add     sp,4          ; remove VERSION arguments
  6744.  
  6745.                 mov     ah,76         ; function 76: terminate process
  6746.                 xor     al,al         ; errorlevel 0
  6747.                 int     21h           ; exit to DOS
  6748.  
  6749.       main_TEXT ENDS
  6750.                 END     start
  6751.  
  6752. 268  Fastgraph User's Guide
  6753.  
  6754.  
  6755. Appendix C
  6756.  
  6757. Interrupts and Fastgraph
  6758. 270  Fastgraph User's Guide
  6759.  
  6760. Interrupts Used by Fastgraph
  6761.  
  6762.      DOS maintains an interrupt vector table that contains the addresses of
  6763. 256 interrupt handlers, or routines, that perform various functions.  The
  6764. handlers are usually referenced by their hexadecimal interrupt number,
  6765. between 00 and FF.  Of these, only interrupts 60 through 66 and F1 through FF
  6766. are not used by DOS, the ROM BIOS, or other software and are thus available
  6767. for user applications.
  6768.  
  6769.      Certain Fastgraph routines use some of the available interrupts.
  6770. Namely, the fg_music routine uses interrupt 60, the asynchronous sound
  6771. routines (fg_musicb, fg_sounds, and fg_voices) use interrupts 60 and 61, and
  6772. all Fastgraph/Light routines use interrupt 62.  If your program defines its
  6773. own interrupt handlers, it must not use any of the interrupts reserved for
  6774. Fastgraph (unless, of course, it doesn't use any of the Fastgraph routines
  6775. that would create a conflict).
  6776.  
  6777.  
  6778. Extending the Time-of-Day Interrupt
  6779.  
  6780.      As mentioned in Chapter 14, the BIOS time-of-day clock is incremented by
  6781. an interrupt handler.  The routine that does this is interrupt 08, a hardware
  6782. interrupt automatically activated 18.2 times per second.  After incrementing
  6783. the clock, interrupt 08 invokes interrupt 1C, which by default references a
  6784. "do-nothing" interrupt handler.  While changing interrupt 08 can be tricky,
  6785. it is fairly straightforward to define our own handler for interrupt 1C.
  6786. This handler also will be executed automatically 18.2 times per second.
  6787. Example C-1 illustrates how to do this.
  6788.  
  6789.      When we discussed joysticks in Chapter 12, we said there were two ways
  6790. to monitor joystick button status.  One is to intersperse calls to the
  6791. fg_button routine at strategic places in your program and then take necessary
  6792. action depending on the button status.  However, the problem with this scheme
  6793. is the chance of missing a button press -- if you press the joystick button
  6794. and then release it between calls to fg_button, the program will not detect
  6795. the joystick activity.  A preferable method is to call fg_button from a
  6796. handler for interrupt 1C, which essentially provides continuous monitoring of
  6797. the joystick buttons.  When we need the button status within our program, all
  6798. we need to do is examine a global variable.
  6799.  
  6800.      Example C-1 consists of a main program (written in C) and an assembly
  6801. language subroutine named int1C (suitable for the medium memory model).  The
  6802. main program calls int1C to define a handler for interrupt 1C.  In response
  6803. to any keystroke (except Escape), the program displays the button press
  6804. information for each joystick since the previous keystroke (refer to the
  6805. discussion of the fg_button routine for the meanings of the status values).
  6806. When you press the Escape key, the program exits to DOS, but not before
  6807. calling int1C to restore the original interrupt 1C handler.
  6808.  
  6809.                          Example C-1 (main program).
  6810.  
  6811.                #include <fastgraf.h>
  6812.                #include <stdio.h>
  6813.                void main(void);
  6814.  
  6815.                #define ESC 27
  6816.  
  6817.                                     Appendix C:  Interrupts and Fastgraph  271
  6818.  
  6819.                int status1, status2;
  6820.  
  6821.                void main()
  6822.                {
  6823.                   unsigned char key, aux;
  6824.  
  6825.                   int1C(1);
  6826.  
  6827.                   status1 = 0;
  6828.                   status2 = 0;
  6829.  
  6830.                   do {
  6831.                      printf("\n");
  6832.                      printf("Joystick 1 status: %d\n",status1);
  6833.                      printf("Joystick 2 status: %d\n",status2);
  6834.                      status1 = 0;
  6835.                      status2 = 0;
  6836.                      fg_getkey(&key,&aux);
  6837.                      }
  6838.                   while (key != ESC);
  6839.  
  6840.                   int1C(0);
  6841.                }
  6842.  
  6843.  
  6844.      We'll now examine the int1C assembly language subroutine.  It actually
  6845. consists of three parts:  a portion to enable our interrupt handler, our
  6846. handler itself, and a portion to disable the handler.  When we call int1C
  6847. with a nonzero argument, it saves the original data segment (so we can access
  6848. the global variables within the handler), saves the original handler's
  6849. address (called the vector) for interrupt 1C, and then enables our handler,
  6850. which takes the form of a far procedure.
  6851.  
  6852.      The handler routine then begins to be activated at 18.2 times per
  6853. second.  After saving all the important registers, the handler calls the
  6854. Fastgraph routine fg_button twice, once for each joystick.  The return values
  6855. are logically ORed with the status1 and status2 C global variables to update
  6856. the button status information.  Finally, the handler restores the original
  6857. registers and returns control to the point of the interrupt.
  6858.  
  6859.      Before the main program exits, it calls int1C with a zero argument to
  6860. restore the original handler for interrupt 1C.  No provision is made in the
  6861. program to check if we had previously defined our own handler (and hence
  6862. saved the original interrupt 1C vector), but this could be added with little
  6863. difficulty.
  6864.  
  6865.                  Example C-1 (assembly language subroutine).
  6866.  
  6867.  
  6868.              EXTRN   _status1:word ; C global variable for button 1 status
  6869.  
  6870.              EXTRN   _status2:word ; C global variable for button 2 status
  6871.  
  6872.              EXTRN   _fg_button:far ; Fastgraph routine
  6873.  
  6874. 272  Fastgraph User's Guide
  6875.  
  6876.   int1C_TEXT SEGMENT byte public 'CODE'
  6877.  
  6878.              ASSUME  cs:int1C_TEXT
  6879.  
  6880.  
  6881.   int1C_CS   dw      ?             ; holds original INT 1C segment address
  6882.  
  6883.   int1C_IP   dw      ?             ; holds original INT 1C offset
  6884.  
  6885.   orig_DS    dw      ?             ; holds original data segment
  6886.  
  6887.  
  6888.  
  6889.   _int1C     PROC    far
  6890.  
  6891.              PUBLIC  _int1C
  6892.  
  6893.  
  6894.  
  6895.              push    bp            ; save caller's BP register
  6896.  
  6897.              mov     bp,sp         ; make BP point to argument list
  6898.  
  6899.              push    si            ; save caller's SI register
  6900.  
  6901.              push    di            ; save caller's DI register
  6902.  
  6903.  
  6904.  
  6905.              mov     dx,[bp+6]     ; get the flag parameter
  6906.  
  6907.              or      dx,dx         ; replace the old interrupt handler?
  6908.  
  6909.              jz      replace       ; yes, branch to that processing
  6910.  
  6911.  
  6912.  
  6913.   ; define a new handler for INT 1C
  6914.  
  6915.  
  6916.  
  6917.   define:    mov     ax,ds         ; put current data segment in AX
  6918.  
  6919.              mov     cs:orig_DS,ax ; save it in the control information area
  6920.  
  6921.  
  6922.  
  6923.              mov     al,1Ch        ; interrupt vector to save
  6924.  
  6925.              mov     ah,53         ; function 53: get interrupt vector
  6926.  
  6927.              int     21h           ; get the interrupt vector
  6928.  
  6929.              mov     cs:int1C_CS,es; save the segment
  6930.  
  6931.              mov     cs:int1C_IP,bx; save the offset
  6932.  
  6933.                                     Appendix C:  Interrupts and Fastgraph  273
  6934.  
  6935.  
  6936.  
  6937.              push    ds            ; save our DS register
  6938.  
  6939.              mov     dx,offset handler ; get offset of interrupt handler
  6940.  
  6941.              mov     ax,seg handler; get segment of interrupt handler
  6942.  
  6943.              mov     ds,ax         ; put it in DS
  6944.  
  6945.              mov     al,1Ch        ; interrupt vector to change
  6946.  
  6947.              mov     ah,37         ; function 37: set interrupt vector
  6948.  
  6949.              int     21h           ; change the INT 1C vector to our handler
  6950.  
  6951.              pop     ds            ; restore our DS register
  6952.  
  6953.  
  6954.  
  6955.              jmp     short return  ; return to the caller
  6956.  
  6957.  
  6958.  
  6959.   ; replace the original handler for INT 1C
  6960.  
  6961.  
  6962.  
  6963.   replace:   push    ds            ; save our DS register
  6964.  
  6965.              mov     dx,cs:int1C_IP; put original INT 1C offset in DX
  6966.  
  6967.              mov     ds,cs:int1C_CS; put original INT 1C segment in DS
  6968.  
  6969.              mov     ah,37         ; function 37: set interrupt vector
  6970.  
  6971.              mov     al,1Ch        ; interrupt vector 1C
  6972.  
  6973.              int     21h           ; restore original INT 1C vector
  6974.  
  6975.              pop     ds            ; restore our DS register
  6976.  
  6977.  
  6978.  
  6979.   return:    xor     ax,ax         ; in case int1C was called as a function
  6980.  
  6981.              pop     di            ; restore our DI register
  6982.  
  6983.              pop     si            ; restore our SI register
  6984.  
  6985.              pop     bp            ; restore our BP register
  6986.  
  6987.              ret
  6988.  
  6989.  
  6990.   _int1C     ENDP
  6991.  
  6992. 274  Fastgraph User's Guide
  6993.  
  6994.  
  6995.  
  6996.   handler    PROC    far           ; interrupt handler that replaces INT 1C
  6997.  
  6998.  
  6999.  
  7000.              cli                   ; disable interrupts while handler active
  7001.  
  7002.              push    ax            ; save registers that may be altered
  7003.  
  7004.              push    bx
  7005.  
  7006.              push    cx
  7007.  
  7008.              push    dx
  7009.  
  7010.              push    di
  7011.  
  7012.              push    si
  7013.  
  7014.              push    ds
  7015.  
  7016.              push    es
  7017.  
  7018.  
  7019.  
  7020.              mov     ds,cs:orig_DS ; retrieve the original data segment
  7021.  
  7022.  
  7023.  
  7024.              mov     ax,1          ; use joystick 1
  7025.  
  7026.              push    ax            ; pass joystick number to button routine
  7027.  
  7028.              call    _fg_button    ; AX = button status for joystick 1
  7029.  
  7030.              add     sp,2          ; remove the argument
  7031.  
  7032.              or      _status1,ax   ; update status variable for joystick 1
  7033.  
  7034.  
  7035.  
  7036.              mov     ax,2          ; use joystick 2
  7037.  
  7038.              push    ax            ; pass joystick number to button routine
  7039.  
  7040.              call    _fg_button    ; AX = button status for joystick 2
  7041.  
  7042.              add     sp,2          ; remove the argument
  7043.  
  7044.              or      _status2,ax   ; update status variable for joystick 2
  7045.  
  7046.  
  7047.  
  7048.              pop     es            ; restore altered registers
  7049.  
  7050.                                     Appendix C:  Interrupts and Fastgraph  275
  7051.  
  7052.              pop     ds
  7053.  
  7054.              pop     si
  7055.  
  7056.              pop     di
  7057.  
  7058.              pop     dx
  7059.  
  7060.              pop     cx
  7061.  
  7062.              pop     bx
  7063.  
  7064.              pop     ax
  7065.  
  7066.              iret                  ; return from the interrupt routine
  7067.  
  7068.  
  7069.  
  7070.   handler    ENDP
  7071.  
  7072.  
  7073.  
  7074.   int1C_TEXT ENDS
  7075.  
  7076.              END
  7077.  
  7078.  
  7079.  
  7080.  
  7081.      The example just presented is not meant to be a tutorial on interrupts;
  7082. there are many good references on DOS that explain them in detail.  However,
  7083. an example specific to Fastgraph should be helpful.
  7084. 276  Fastgraph User's Guide
  7085.  
  7086.  
  7087. Appendix D
  7088.  
  7089. Contents of the
  7090. Compiler-Specific Libraries
  7091. 278  Fastgraph User's Guide
  7092.  
  7093.  
  7094.      For each of the supported Fastgraph compilers except QuickBASIC, there
  7095. is a compiler-specific Fastgraph library (also called the extended Fastgraph
  7096. library) that contains the following routines:
  7097.  
  7098.  
  7099.            fg_circlew     fg_getworld    fg_rectw       fg_setworld
  7100.            fg_clprect     fg_initw       fg_restorew    fg_swchar
  7101.            fg_dashrw      fg_moverw      fg_savew       fg_swlength
  7102.            fg_dashw       fg_movew       fg_setangle    fg_swtext
  7103.            fg_drawrw      fg_paintw      fg_setclipw    fg_xscreen
  7104.            fg_draww       fg_panw        fg_setratio    fg_xworld
  7105.            fg_drectw      fg_pointw      fg_setsize     fg_yscreen
  7106.            fg_ellipsew    fg_polygonw    fg_setsizew    fg_yworld
  7107.  
  7108.  
  7109. These routines use the world space coordinate system, either directly or
  7110. internally.  Note that none of them are included in Fastgraph/Light.
  7111.  
  7112.      As mentioned in Chapter 1, if your program uses any of these routines,
  7113. you must link it with the standard Fastgraph library (FGx.LIB) and the
  7114. compiler-specific Fastgraph library (FGcccx.LIB).
  7115.                                                                     Index  279
  7116.  
  7117.                                   I n d e x
  7118.  
  7119. 8253-5 programmable timer chip  234
  7120. Active page  119
  7121. Animation  188
  7122.      dynamic frame  194
  7123.      dynamic page flipping  196
  7124.      page flipping  196
  7125.      simple  188
  7126.      static frame  192
  7127.      static page flipping  196
  7128.      summary  198
  7129.      XOR  190
  7130. ANSI.SYS  28, 29
  7131. Assembly language  266
  7132. Attribute  48, 104, 105
  7133. Available memory  254
  7134. Background color  49, 50
  7135. Bit maps  136
  7136.      CGA  141, 142, 149
  7137.      EGA  144, 151
  7138.      filler bits  137
  7139.      Hercules  144
  7140.      MCGA  145
  7141.      memory requirements  172
  7142.      mode-independent  136
  7143.      mode-specific  140
  7144.      PCjr  143, 151
  7145.      retrieving  169
  7146.      subscript order  137, 138, 147
  7147.      Tandy  143, 151
  7148.      text modes  146
  7149.      VGA  144, 145, 151
  7150. Bit-mapped characters  114
  7151. Borland C++  3, 7
  7152. Byte boundary  174, 175
  7153. CapsLock  212-214
  7154. CGA palettes  51
  7155. Character cells  18
  7156. Character space  40, 100
  7157. Characters
  7158.      bit-mapped  114
  7159.      hardware  101
  7160.      software  108
  7161. Circles  83, 84
  7162. Clearing the screen  76
  7163. CLIP  259, 260
  7164.      /M option  259
  7165.      /P option  259
  7166.      /W option  259
  7167. Clipping  76
  7168. Clock tick  248-250
  7169. Clock tick interrupt  239, 241, 248
  7170. Closed shapes  83
  7171. Color  48
  7172. Color indices  69
  7173.  
  7174. 280  Fastgraph User's Guide
  7175.  
  7176. Color number  50
  7177. Color value  50
  7178. Compilation  5
  7179. Compiler-specific Fastgraph library  278
  7180. CONVERT  261
  7181.      /PPR switch  261
  7182.      /SPR switch  261
  7183. Coordinate conversion  44, 107
  7184. Current color  50
  7185. Cursor mask  220, 222
  7186. Dash pattern  82
  7187. Delay units  249, 250
  7188. Display patterns  158
  7189.      CGA  159, 160
  7190.      EGA  161
  7191.      Hercules  161
  7192.      MCGA  162, 163
  7193.      PCjr  160
  7194.      Tandy  160
  7195.      VGA  162, 163
  7196. Dithering  88
  7197. Dithering matrix  89
  7198.      alignment  94
  7199.      CGA  89, 90
  7200.      EGA  92
  7201.      Hercules  91
  7202.      MCGA  93
  7203.      PCjr  91
  7204.      Tandy  91
  7205.      VGA  92, 93
  7206. EDITSPR  261, 262
  7207. Ellipses  83, 84
  7208. EMM386.EXE  129
  7209. EMS  129
  7210. Expanded memory  129
  7211. Expanded Memory Manager  129
  7212. Extended Fastgraph library  278
  7213. Extended memory  129
  7214. Fade  66, 67
  7215. FASTGRAF.BI  6
  7216. FASTGRAF.H  5
  7217. Fastgraph  2
  7218. Fastgraph routines
  7219.      fg_allocate  122, 124, 125, 127, 129, 132, 175, 178, 254
  7220.      fg_alloccms  129
  7221.      fg_allocems  129, 132
  7222.      fg_allocxms  129, 132
  7223.      fg_automode  33, 34, 36, 77, 84, 86, 206
  7224.      fg_bestmode  30, 34, 35, 36, 95, 122, 124, 125
  7225.      fg_box  87, 96
  7226.      fg_boxdepth  87, 88, 96
  7227.      fg_button  228, 229, 231, 270, 271
  7228.      fg_capslock  213, 231
  7229.      fg_chgattr  104, 114
  7230.      fg_chgtext  104, 114
  7231.      fg_circle  84, 85, 96
  7232.  
  7233. Fastgraph routines (continued)
  7234.      fg_circlew  84, 96
  7235.      fg_clipmask  166, 167, 184
  7236.      fg_clpimage  148, 149, 150, 166, 167, 169, 184
  7237.      fg_clprect  86, 96, 188, 195, 196
  7238.      fg_clprectw  86, 96
  7239.      fg_copypage  129, 131, 133, 175, 176, 184
  7240.      fg_cursor  28, 36, 73, 105, 178
  7241.      fg_dash  82, 96
  7242.      fg_dashrel  82, 97
  7243.      fg_dashrw  82, 97
  7244.      fg_dashw  82, 97
  7245.      fg_defcolor  70, 73, 94
  7246.      fg_dispfile  157, 158, 184, 198, 258
  7247.      fg_display  153-158, 184, 198
  7248.      fg_displayp  154, 155, 156-158, 184, 198
  7249.      fg_disppcx  164, 166, 184
  7250.      fg_draw  79, 80, 97, 204
  7251.      fg_drawmap  114, 136, 138-141, 152, 166, 168-172, 181, 185, 198,
  7252.           222, 226
  7253.      fg_drawmask  166, 167, 168, 185
  7254.      fg_drawrel  79, 80, 95, 97
  7255.      fg_drawrw  79, 97
  7256.      fg_draww  79, 97
  7257.      fg_drect  88, 89, 92, 93, 94, 97
  7258.      fg_drectw  89, 94, 97
  7259.      fg_drwimage  114, 141, 142-144, 146, 147, 148-150, 152, 166,
  7260.           167-169, 172, 185, 198, 226
  7261.      fg_egacheck  32, 36
  7262.      fg_ellipse  84, 85, 97, 192
  7263.      fg_ellipsew  84, 97
  7264.      fg_erase  76, 97
  7265.      fg_fadein  200, 201, 208
  7266.      fg_fadeout  200, 208
  7267.      fg_flipmask  166, 167, 185
  7268.      fg_flpimage  149, 150, 166, 167, 169, 185
  7269.      fg_freepage  122, 124, 125, 129, 132, 133, 254
  7270.      fg_getaddr  127, 128, 133
  7271.      fg_getattr  105, 114
  7272.      fg_getchar  105, 114
  7273.      fg_getclock  249, 251
  7274.      fg_getcolor  49-51, 57, 73
  7275.      fg_getdacs  66, 67, 73
  7276.      fg_gethpage  176, 185
  7277.      fg_getimage  105, 169, 172, 173, 185, 198
  7278.      fg_getindex  73
  7279.      fg_getkey  212, 231
  7280.      fg_getlines  31, 36
  7281.      fg_getmap  169-173, 181, 185, 198
  7282.      fg_getmaxx  41, 42, 44, 86
  7283.      fg_getmaxy  41, 42, 44, 86
  7284.      fg_getmode  30, 36, 266
  7285.      fg_getpage  127, 133
  7286.      fg_getpixel  76, 77, 97
  7287.      fg_getrgb  65, 66, 73
  7288.      fg_getvpage  127, 133
  7289.      fg_getworld  43, 44
  7290.      fg_getxjoy  228-231
  7291.  
  7292. 282  Fastgraph User's Guide
  7293.  
  7294. Fastgraph routines (continued)
  7295.      fg_getxpos  79, 97
  7296.      fg_getyjoy  228-231
  7297.      fg_getypos  79, 97
  7298.      fg_hush  240, 242, 244
  7299.      fg_hushnext  240, 242, 243, 244
  7300.      fg_imagesiz  172, 173, 185
  7301.      fg_initems  129, 132, 133
  7302.      fg_initjoy  132, 227, 228, 231
  7303.      fg_initw  42, 44, 79, 108, 109
  7304.      fg_initxms  129, 132, 133
  7305.      fg_intjoy  229-231
  7306.      fg_intkey  212, 213, 229, 231, 242, 248, 249
  7307.      fg_locate  101-103, 107, 114, 120, 126, 173
  7308.      fg_makepcx  164, 166, 185
  7309.      fg_maprgb  68, 73
  7310.      fg_measure  250, 251
  7311.      fg_memavail  254, 256
  7312.      fg_mousebut  218, 219, 231
  7313.      fg_mousecur  220, 221, 231
  7314.      fg_mouseini  132, 215, 216, 219, 231
  7315.      fg_mouselim  216, 217, 231
  7316.      fg_mousemov  216, 217, 231
  7317.      fg_mousepos  218, 219, 231
  7318.      fg_mouseptr  220, 225, 231
  7319.      fg_mousespd  217, 231
  7320.      fg_mousevis  216, 217, 219, 232
  7321.      fg_move  79, 80, 82, 95, 98, 139, 140, 156, 170, 173, 181, 204
  7322.      fg_moverel  79, 80, 98
  7323.      fg_moverw  79, 98
  7324.      fg_movew  79, 98
  7325.      fg_music  237-239, 242, 244, 270
  7326.      fg_musicb  242-244, 270
  7327.      fg_numlock  213, 232
  7328.      fg_paint  95, 98, 204
  7329.      fg_paintw  95, 98
  7330.      fg_palette  51-60, 62, 64, 65, 68, 69, 74
  7331.      fg_palettes  69, 74
  7332.      fg_pan  205-208
  7333.      fg_panw  205, 206, 208
  7334.      fg_pattern  158, 159, 163, 185
  7335.      fg_playing  240, 243, 244
  7336.      fg_point  76, 77, 98
  7337.      fg_pointw  76, 98
  7338.      fg_polygon  83, 98
  7339.      fg_polygonw  83, 98
  7340.      fg_quiet  234, 236, 237, 244
  7341.      fg_rect  60, 65, 86, 87, 88, 98, 107, 120, 138, 141, 178, 188, 195
  7342.      fg_rectw  86, 98, 113
  7343.      fg_reset  29, 30, 36, 266
  7344.      fg_resize  131-133, 207, 208
  7345.      fg_restore  176-180, 185, 195, 201
  7346.      fg_restorew  177, 185
  7347.      fg_resume  243, 244
  7348.      fg_revimage  149, 150, 166, 167, 169, 185
  7349.      fg_revmask  166, 167, 185
  7350.  
  7351.                                                                     Index  283
  7352.  
  7353. Fastgraph routines (continued)
  7354.      fg_save  176-180, 185
  7355.      fg_savew  177, 185
  7356.      fg_scrlock  213, 232
  7357.      fg_scroll  202-204, 208
  7358.      fg_setangle  112, 114
  7359.      fg_setattr  48-50, 74, 101, 102, 104, 114, 120, 121, 123, 125
  7360.      fg_setcaps  214, 232
  7361.      fg_setclip  76, 98, 148
  7362.      fg_setclipw  76, 98
  7363.      fg_setcolor  28, 49, 50, 51-60, 62, 64, 65, 74, 76, 79, 82, 92, 93,
  7364.           101, 104, 108, 115, 120, 121, 123, 125, 138, 189, 190, 202,
  7365.           203
  7366.      fg_setdacs  66, 67, 74, 263
  7367.      fg_setfunc  190, 255, 256
  7368.      fg_sethpage  176, 177, 178, 185, 200, 202
  7369.      fg_setlines  31, 36
  7370.      fg_setmode  28, 30, 37, 50, 51, 57, 64, 69, 70, 76, 77, 79, 84, 86,
  7371.           91, 92, 101, 102, 104, 109, 119, 120, 126, 132, 151, 159, 160,
  7372.           161, 162, 210, 215, 227, 266
  7373.      fg_setnum  214, 232
  7374.      fg_setpage  119, 120, 133, 177
  7375.      fg_setratio  109, 111, 115
  7376.      fg_setrgb  53, 56, 60, 62, 64-66, 68, 73, 74, 163
  7377.      fg_setsize  109, 115
  7378.      fg_setsizew  109, 115
  7379.      fg_setvpage  119, 128, 133, 196, 216
  7380.      fg_setworld  42-44, 109
  7381.      fg_sound  234-237, 239, 240, 245
  7382.      fg_sounds  239, 240, 242, 245, 270
  7383.      fg_stall  249-251
  7384.      fg_suspend  243-245
  7385.      fg_swchar  108-113, 115
  7386.      fg_swlength  113, 115
  7387.      fg_swtext  112, 113, 115
  7388.      fg_tcmask  183, 185
  7389.      fg_tcxfer  183, 186
  7390.      fg_testmode  29, 30, 35, 37, 120, 122, 151, 177, 236
  7391.      fg_text  28, 101, 102, 103, 104, 108, 115, 119
  7392.      fg_transfer  179, 180, 181-183, 186, 194, 195, 196, 201
  7393.      fg_version  5, 266
  7394.      fg_voice  235-237, 239, 240, 241, 245
  7395.      fg_voices  240-242, 245, 270
  7396.      fg_waitfor  66, 188, 194, 196, 204, 206, 213, 217, 237, 248-251
  7397.      fg_waitkey  29, 212, 232
  7398.      fg_where  102, 103, 115, 126
  7399.      fg_xalpha  44, 107, 115
  7400.      fg_xconvert  44, 45, 107, 115
  7401.      fg_xscreen  44, 45, 77
  7402.      fg_xworld  44, 45, 79
  7403.      fg_yalpha  44, 107, 115
  7404.      fg_yconvert  44, 45, 107, 115
  7405.      fg_yscreen  44, 45, 77
  7406.      fg_yworld  44, 45, 79
  7407. Fastgraph/Light  2
  7408. Fastgraph/Light Video Driver  2, 16
  7409.  
  7410. 284  Fastgraph User's Guide
  7411.  
  7412. FGDRIVER  16
  7413.      /U option  16
  7414. FGTP unit  6
  7415. FGTPX unit  6
  7416. Filler bits  137
  7417. Foreground color  48, 49
  7418. FORTRAN see Microsoft FORTRAN
  7419. Game port  227
  7420. GrabRGB  158, 262, 263
  7421.      /D option  263
  7422.      output file format  263
  7423. Graphics cursor  79
  7424. Graphics modes  18, 21, 50
  7425.      CGA  21, 51, 52
  7426.      EGA  23, 56, 58, 59
  7427.      extended VGA  24
  7428.      Hercules  22, 54, 55
  7429.      MCGA  24, 61, 64
  7430.      native EGA  23
  7431.      native VGA  24
  7432.      PCjr  22, 53
  7433.      Tandy  53
  7434.      Tandy 1000  22
  7435.      VGA  24, 61, 63, 64
  7436. Hardware characters  101
  7437.      graphics modes  105
  7438.      side effects  106
  7439.      text modes  101
  7440. HERCFIX  263
  7441. Hidden page  119, 176
  7442. HIMEM.SYS  129
  7443. Hot spot  224
  7444. Image array  147
  7445. Image transfer routines  175
  7446. Images  136
  7447.      clipped  148
  7448.      regular  141
  7449.      reversed  149
  7450.      reversed clipped  149
  7451. INCLUDE environment variable  5, 6
  7452. Input devices  210
  7453. INSTALL program  4
  7454.      /L option  4
  7455. Installation  4
  7456. Interrupts  270
  7457. INTRFACE.FOR  6
  7458. Joystick  227
  7459.      button status  228, 229, 270
  7460.      calibration  228
  7461.      characteristics  228
  7462.      horizontal position  228
  7463.      initialize  227
  7464.      keyboard emulation  229
  7465.      special considerations  230
  7466.      vertical position  228
  7467.  
  7468.                                                                     Index  285
  7469. Keyboard  210
  7470.      extended codes  210
  7471.      standard codes  210
  7472. Keyboard buffer  212, 249
  7473. Keyboard state light  214
  7474. Lines
  7475.      dashed  82
  7476.      solid  79
  7477. Linking  5
  7478. Logical pages  129
  7479.      creating  129
  7480.      releasing  129
  7481. Masking map  166, 167
  7482. Memory models  3
  7483.      large  3
  7484.      medium  3
  7485.      small  3
  7486. Memory update function  255
  7487. Mickeys  217
  7488. Microsoft C  3, 8
  7489. Microsoft FORTRAN  3, 9
  7490. Microsoft Mouse  215
  7491. Microsoft QuickBASIC  3, 10
  7492. Microsoft QuickC  3, 11
  7493. Mode X  26
  7494. Mouse  214
  7495.      button status  218
  7496.      CGA Considerations  226
  7497.      cursor  216, 220
  7498.      cursor mask  220, 222
  7499.      cursor visibility  216
  7500.      default cursor  222
  7501.      hot spot  224
  7502.      initialize  215
  7503.      limits  216
  7504.      position  216, 218
  7505.      screen mask  220, 222
  7506.      screen updates  216
  7507.      speed  217
  7508. Mouse cursor  216, 220
  7509.      graphics modes  222
  7510.      hot spot  224
  7511.      text modes  220
  7512. Mouse driver  215
  7513. Music  237
  7514.      asynchronous  242
  7515.      restarting  243
  7516.      stopping  242
  7517.      suspending  243
  7518.      synchronous  237
  7519. Music commands  237
  7520. Music string  237, 242
  7521. Musical notes  237
  7522. Naming conventions  4
  7523. NumLock  212-214
  7524. Overscan  51
  7525. Packed pixel run map  154, 155
  7526.  
  7527. 286  Fastgraph User's Guide
  7528.  
  7529. Palette  19
  7530. Palette number  53, 56, 58, 59, 62
  7531. Palette registers  53, 56, 58, 59, 61, 63, 69, 70
  7532. Palette value  53, 56, 58, 59
  7533. Palettes  53, 56, 58, 59, 61, 63
  7534. Panning  131, 207
  7535. PC Paintbrush  164
  7536. PCOPTION environment variable  5
  7537. PCX file
  7538.      creating  164
  7539.      displaying  164
  7540.      video mode compatibility  165
  7541. PCX images  164
  7542. Periodic noise  236
  7543. Physical pages  118
  7544. Pixel bleeding  226
  7545. Pixel run  152
  7546. Pixel run file  156-158, 258
  7547. Pixel run map  152, 153, 158
  7548. Pixels  18
  7549. Points  76
  7550. Polygons  83
  7551. Power C  3, 13
  7552. Put_string  103
  7553. QuickBASIC see Microsoft QuickBASIC
  7554. QuickC see Microsoft QuickC
  7555. Real-time operations  248
  7556. Rectangles
  7557.      dithered  88
  7558.      solid  86
  7559.      unfilled  87
  7560. Region fill  95
  7561. Register preservation  266
  7562. Resolution  18
  7563. Reverse video  104
  7564. RGB color mapping  68
  7565. Screen dissolving  200
  7566. Screen mask  220, 222
  7567. Screen origin  205
  7568. Screen space  40, 41
  7569. Scrolling  202
  7570.      circular  202
  7571.      end-off  202
  7572. Scrolling increment  202
  7573. Scrolling region  202
  7574. ScrollLock  212, 213
  7575. Shadow  104
  7576. Sliding tone  235
  7577. SNAPSHOT  158, 258, 259, 262, 263
  7578.      error tone  258
  7579.      image files  258
  7580.      success tone  258
  7581. Software characters  108
  7582.      alternate font  108, 109, 112
  7583.      angle  112
  7584.      aspect ratio  109
  7585.  
  7586. Software characters (continued)
  7587.      font change operator (\)  109
  7588.      primary font  108, 109
  7589.      size  109
  7590.      string length  113
  7591.      subscript operator (\v)  110
  7592.      superscript operator (\^)  110
  7593.      underline operator (_)  110
  7594. Sound  234
  7595.      asynchronous  239
  7596.      disk accesses during  239
  7597.      duration  234
  7598.      frequency  234
  7599.      PCjr  234
  7600.      stopping  242
  7601.      synchronous  234
  7602.      Tandy  234
  7603.      volume  234
  7604. Sound effects  234-236
  7605. Splitter cable  227Standard color set  50
  7606. Strlen  103
  7607. Stroke characters  108
  7608. Texas Instruments SN76496A sound chip  234
  7609. Text cursor  28, 101, 126
  7610. Text modes  18, 19, 48
  7611.      43 lines  31
  7612.      50 lines  31
  7613.      color  48
  7614.      monochrome  49
  7615. TI sound chip  234
  7616. Transparent color  183
  7617. Turbo C  3, 14
  7618. Turbo C++  3, 14
  7619. Turbo Pascal  3, 15
  7620. Utilities  258
  7621. Vector characters  108
  7622. Video DAC registers  61, 62, 63-66, 69
  7623. Video modes  18
  7624.      mode 00  20
  7625.      mode 01  20
  7626.      mode 02  20
  7627.      mode 03  20
  7628.      mode 04  21
  7629.      mode 05  21
  7630.      mode 06  22
  7631.      mode 07  20
  7632.      mode 09  22
  7633.      mode 11  23
  7634.      mode 12  23
  7635.      mode 13  23
  7636.      mode 14  24
  7637.      mode 15  24
  7638.      mode 16  24
  7639.      mode 17  25
  7640.      mode 18  25
  7641.      mode 19  25
  7642.      mode 20  25
  7643.  
  7644.                                                                     Index  287
  7645. Video modes (continued)
  7646.      mode 21  25
  7647.      mode 22  26
  7648.      mode 23  26
  7649.      mode X  26
  7650.      summary  18
  7651. Video page  118
  7652. Video page resizing  207
  7653. Video pages  19
  7654.      active  119
  7655.      hidden  119, 176
  7656.      information  127
  7657.      logical  129
  7658.      physical  118
  7659.      resizing  131
  7660.      segment address  127
  7661.      virtual  118, 122
  7662.      visual  119
  7663. Video subsystem  19
  7664. Virtual colors  69, 70
  7665. Virtual pages  118
  7666.      creating  122
  7667.      releasing  122
  7668.      special considerations  128
  7669. Visual effects  201
  7670. Visual page  119
  7671. Warbling  235
  7672. White noise  236
  7673. World space  40, 42
  7674. XMS  129